diff --git a/.gitignore b/.gitignore
index 3c4efe2..fc68272 100644
--- a/.gitignore
+++ b/.gitignore
@@ -258,4 +258,7 @@ paket-files/
# Python Tools for Visual Studio (PTVS)
__pycache__/
-*.pyc
\ No newline at end of file
+*.pyc
+
+# Claude Code project-specific instructions
+CLAUDE.md
\ No newline at end of file
diff --git a/README.md b/README.md
index b0a7c58..63c889a 100644
--- a/README.md
+++ b/README.md
@@ -9,4 +9,21 @@ CgLogListener

+
目錄下可替換wav
+
+York
+20260128
+1. 增加 smtp mailsettings (暫時只使用 gmail 進行測試)。
+2. 新增物品損壞通知。
+3. 設定應用來源,方便信件過濾。
+4. 新增吃料偵測,秒數循環提醒。
+
+20260203
+1. 預設選項可由 setting.ini 中自由修改命名、regex 規則。
+2. 吃料偵測改成計時器功能,可自定義秒數、提示訊息、regex 規則,若須恢復吃料判斷,案預設即可。
+3. custom notify 路徑設定改成跟選擇魔力資料夾相同,不用再手動打。
+4. custom notify 是否啟用通知,改成跟 sound, mail 一樣,可自行勾選是否啟用。
+5. 自訂關鍵字功能,可自行增加、修改,並增加 sound mail, notify, regex 彈性設定。
+
+
diff --git a/src/CgLogListener/CgLogListener.csproj b/src/CgLogListener/CgLogListener.csproj
index 7685266..26029f2 100644
--- a/src/CgLogListener/CgLogListener.csproj
+++ b/src/CgLogListener/CgLogListener.csproj
@@ -22,9 +22,11 @@
false
false
true
- 0
+ true
+ 1
2.1.0.%2a
false
+ true
true
@@ -51,6 +53,18 @@
icon.ico
+
+ 76921EC744D0212480757F6181BD1C3D8ADB9734
+
+
+ CgLogListener_TemporaryKey.pfx
+
+
+ true
+
+
+ true
+
..\packages\ini-parser.2.5.2\lib\net20\INIFileParser.dll
@@ -96,7 +110,10 @@
Resource.resx
+
+
+
@@ -116,6 +133,7 @@
Resource.Designer.cs
+
diff --git a/src/CgLogListener/CgLogListenerControls.cs b/src/CgLogListener/CgLogListenerControls.cs
index 9badeb0..807fcaf 100644
--- a/src/CgLogListener/CgLogListenerControls.cs
+++ b/src/CgLogListener/CgLogListenerControls.cs
@@ -12,18 +12,18 @@ public class CgLogListenerCheckBox : CheckBox, INotifyMessage
public string NameInSetting { get; set; }
public string RegexPattern { get; set; }
- public bool Notify(string message)
+ public NotifyResult Notify(string message)
{
var settings = Settings.GetInstance();
- if (settings.StandardTips.TryGetValue(NameInSetting, out bool value) &&
- value &&
+ if (settings.StandardTips.TryGetValue(NameInSetting, out TipNotifyOptions options) &&
+ options.Enabled &&
Regex.IsMatch(message, RegexPattern))
{
- return true;
+ return NotifyResult.Match(options.PlaySound, options.SendMail, options.CustomNotify);
}
- return false;
+ return NotifyResult.NoMatch;
}
}
@@ -36,29 +36,54 @@ public class CgLogListenerListBox : ListBox, INotifyMessage
{
public NotifyIcon NotifyIcon { get; set; }
- public bool Notify(string message)
+ public NotifyResult Notify(string message)
{
var settings = Settings.GetInstance();
- foreach (var s in settings.CustomizeTips)
+ foreach (var kv in settings.CustomizeTips)
{
- var split = s.Split('|');
+ var keyword = kv.Key;
+ var options = kv.Value;
- if (message.Contains(split[0]))
+ if (!options.Enabled) continue;
+
+ var split = keyword.Split('|');
+ var pattern = split[0];
+
+ bool isMatch;
+ if (options.IsRegex)
+ {
+ try
+ {
+ isMatch = Regex.IsMatch(message, pattern);
+ }
+ catch
+ {
+ isMatch = false;
+ }
+ }
+ else
+ {
+ isMatch = message.Contains(pattern);
+ }
+
+ if (isMatch)
{
if (split.Length > 1)
{
var exps = split[1].Split(',');
-
- return !exps.Any(x => message.Contains(x));// !message.Contains(split[1]);
+ if (!exps.Any(x => message.Contains(x)))
+ {
+ return NotifyResult.Match(options.PlaySound, options.SendMail, options.CustomNotify);
+ }
}
else
{
- return true;
+ return NotifyResult.Match(options.PlaySound, options.SendMail, options.CustomNotify);
}
}
}
- return false;
+ return NotifyResult.NoMatch;
}
}
}
diff --git a/src/CgLogListener/FormMain.Designer.cs b/src/CgLogListener/FormMain.Designer.cs
index f8daf15..6117a38 100644
--- a/src/CgLogListener/FormMain.Designer.cs
+++ b/src/CgLogListener/FormMain.Designer.cs
@@ -1,4 +1,4 @@
-namespace CgLogListener
+namespace CgLogListener
{
partial class FormMain
{
@@ -38,10 +38,18 @@ private void InitializeComponent()
this.toolExit = new System.Windows.Forms.ToolStripMenuItem();
this.txtCgLogPath = new System.Windows.Forms.TextBox();
this.btnSelectLogPath = new System.Windows.Forms.Button();
+ this.lblAppName = new System.Windows.Forms.Label();
+ this.txtAppName = new System.Windows.Forms.TextBox();
this.panel1 = new System.Windows.Forms.Panel();
- this.checkBox1 = new System.Windows.Forms.CheckBox();
+ this.cgLogListenerCheckBox7 = new CgLogListener.CgLogListenerCheckBox();
+ this.chkCookingReminder = new System.Windows.Forms.CheckBox();
+ this.txtCookingInterval = new System.Windows.Forms.TextBox();
+ this.lblCookingUnit = new System.Windows.Forms.Label();
+ this.txtCookingPattern = new System.Windows.Forms.TextBox();
+ this.txtCookingMessage = new System.Windows.Forms.TextBox();
+ this.btnCookingDefault = new System.Windows.Forms.Button();
this.cgLogListenerTrackBar = new CgLogListener.CgLogListenerTrackBar();
- this.cgLogListenerSettingCheckBox1 = new CgLogListener.CgLogListenerCheckBox();
+ this.lblSoundVol = new System.Windows.Forms.Label();
this.cgLogListenerCheckBox6 = new CgLogListener.CgLogListenerCheckBox();
this.cgLogListenerCheckBox5 = new CgLogListener.CgLogListenerCheckBox();
this.cgLogListenerCheckBox4 = new CgLogListener.CgLogListenerCheckBox();
@@ -49,9 +57,15 @@ private void InitializeComponent()
this.label1 = new System.Windows.Forms.Label();
this.cgLogListenerListBox = new CgLogListener.CgLogListenerListBox();
this.btnDelCus = new System.Windows.Forms.Button();
+ this.btnEditCus = new System.Windows.Forms.Button();
this.btnAddCus = new System.Windows.Forms.Button();
this.cgLogListenerCheckBox2 = new CgLogListener.CgLogListenerCheckBox();
this.cgLogListenerCheckBox1 = new CgLogListener.CgLogListenerCheckBox();
+ this.txtCustomNotifier = new System.Windows.Forms.TextBox();
+ this.lblCustomNotifier = new System.Windows.Forms.Label();
+ this.btnSelectNotifier = new System.Windows.Forms.Button();
+ this.timerCooking = new System.Windows.Forms.Timer(this.components);
+ this.btnSaveAppName = new System.Windows.Forms.Button();
this.btnExit = new System.Windows.Forms.Button();
this.linkLabel1 = new System.Windows.Forms.LinkLabel();
this.notifyIconContextMenu.SuspendLayout();
@@ -78,46 +92,49 @@ private void InitializeComponent()
this.toolExit});
this.notifyIconContextMenu.Name = "notifyIconContextMenu";
this.notifyIconContextMenu.ShowImageMargin = false;
- this.notifyIconContextMenu.Size = new System.Drawing.Size(86, 76);
+ this.notifyIconContextMenu.Size = new System.Drawing.Size(99, 82);
//
// toolOpen
//
this.toolOpen.Name = "toolOpen";
- this.toolOpen.Size = new System.Drawing.Size(85, 22);
+ this.toolOpen.Size = new System.Drawing.Size(98, 24);
this.toolOpen.Text = "開啟";
this.toolOpen.Click += new System.EventHandler(this.ToolOpen_Click);
//
// toolMinsize
//
this.toolMinsize.Name = "toolMinsize";
- this.toolMinsize.Size = new System.Drawing.Size(85, 22);
+ this.toolMinsize.Size = new System.Drawing.Size(98, 24);
this.toolMinsize.Text = "最小化";
this.toolMinsize.Click += new System.EventHandler(this.ToolMinsize_Click);
//
// toolSep1
//
this.toolSep1.Name = "toolSep1";
- this.toolSep1.Size = new System.Drawing.Size(82, 6);
+ this.toolSep1.Size = new System.Drawing.Size(95, 6);
//
// toolExit
//
this.toolExit.Name = "toolExit";
- this.toolExit.Size = new System.Drawing.Size(85, 22);
+ this.toolExit.Size = new System.Drawing.Size(98, 24);
this.toolExit.Text = "結束";
this.toolExit.Click += new System.EventHandler(this.ToolExit_Click);
//
// txtCgLogPath
//
+ this.txtCgLogPath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
this.txtCgLogPath.Location = new System.Drawing.Point(11, 9);
this.txtCgLogPath.Margin = new System.Windows.Forms.Padding(2);
this.txtCgLogPath.Name = "txtCgLogPath";
this.txtCgLogPath.ReadOnly = true;
- this.txtCgLogPath.Size = new System.Drawing.Size(219, 22);
+ this.txtCgLogPath.Size = new System.Drawing.Size(375, 25);
this.txtCgLogPath.TabIndex = 1;
//
// btnSelectLogPath
//
- this.btnSelectLogPath.Location = new System.Drawing.Point(234, 8);
+ this.btnSelectLogPath.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.btnSelectLogPath.Location = new System.Drawing.Point(390, 8);
this.btnSelectLogPath.Margin = new System.Windows.Forms.Padding(2);
this.btnSelectLogPath.Name = "btnSelectLogPath";
this.btnSelectLogPath.Size = new System.Drawing.Size(53, 22);
@@ -126,11 +143,40 @@ private void InitializeComponent()
this.btnSelectLogPath.UseVisualStyleBackColor = true;
this.btnSelectLogPath.Click += new System.EventHandler(this.BtnSelectLogPath_Click);
//
+ // lblAppName
+ //
+ this.lblAppName.AutoSize = true;
+ this.lblAppName.Location = new System.Drawing.Point(11, 72);
+ this.lblAppName.Name = "lblAppName";
+ this.lblAppName.Size = new System.Drawing.Size(71, 15);
+ this.lblAppName.TabIndex = 20;
+ this.lblAppName.Text = "應用名稱:";
+ //
+ // txtAppName
+ //
+ this.txtAppName.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.txtAppName.Location = new System.Drawing.Point(85, 68);
+ this.txtAppName.Margin = new System.Windows.Forms.Padding(2);
+ this.txtAppName.Name = "txtAppName";
+ this.txtAppName.Size = new System.Drawing.Size(299, 25);
+ this.txtAppName.TabIndex = 21;
+ this.txtAppName.Leave += new System.EventHandler(this.TxtAppName_Leave);
+ //
// panel1
//
- this.panel1.Controls.Add(this.checkBox1);
+ this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.panel1.Controls.Add(this.cgLogListenerCheckBox7);
+ this.panel1.Controls.Add(this.chkCookingReminder);
+ this.panel1.Controls.Add(this.txtCookingInterval);
+ this.panel1.Controls.Add(this.lblCookingUnit);
+ this.panel1.Controls.Add(this.txtCookingPattern);
+ this.panel1.Controls.Add(this.txtCookingMessage);
+ this.panel1.Controls.Add(this.btnCookingDefault);
this.panel1.Controls.Add(this.cgLogListenerTrackBar);
- this.panel1.Controls.Add(this.cgLogListenerSettingCheckBox1);
+ this.panel1.Controls.Add(this.lblSoundVol);
this.panel1.Controls.Add(this.cgLogListenerCheckBox6);
this.panel1.Controls.Add(this.cgLogListenerCheckBox5);
this.panel1.Controls.Add(this.cgLogListenerCheckBox4);
@@ -138,56 +184,112 @@ private void InitializeComponent()
this.panel1.Controls.Add(this.label1);
this.panel1.Controls.Add(this.cgLogListenerListBox);
this.panel1.Controls.Add(this.btnDelCus);
+ this.panel1.Controls.Add(this.btnEditCus);
this.panel1.Controls.Add(this.btnAddCus);
this.panel1.Controls.Add(this.cgLogListenerCheckBox2);
this.panel1.Controls.Add(this.cgLogListenerCheckBox1);
- this.panel1.Location = new System.Drawing.Point(11, 38);
+ this.panel1.Location = new System.Drawing.Point(11, 100);
this.panel1.Margin = new System.Windows.Forms.Padding(2);
this.panel1.Name = "panel1";
- this.panel1.Size = new System.Drawing.Size(276, 255);
+ this.panel1.Size = new System.Drawing.Size(433, 315);
this.panel1.TabIndex = 6;
//
- // checkBox1
- //
- this.checkBox1.AutoSize = true;
- this.checkBox1.Location = new System.Drawing.Point(2, 230);
- this.checkBox1.Name = "checkBox1";
- this.checkBox1.Size = new System.Drawing.Size(93, 16);
- this.checkBox1.TabIndex = 13;
- this.checkBox1.Text = "Custom Notify";
- this.checkBox1.UseVisualStyleBackColor = true;
+ // cgLogListenerCheckBox7
+ //
+ this.cgLogListenerCheckBox7.AutoSize = true;
+ this.cgLogListenerCheckBox7.Location = new System.Drawing.Point(2, 147);
+ this.cgLogListenerCheckBox7.Name = "cgLogListenerCheckBox7";
+ this.cgLogListenerCheckBox7.NameInSetting = "7";
+ this.cgLogListenerCheckBox7.RegexPattern = "^(?!.*×\\d+).*壞掉了";
+ this.cgLogListenerCheckBox7.Size = new System.Drawing.Size(119, 19);
+ this.cgLogListenerCheckBox7.TabIndex = 18;
+ this.cgLogListenerCheckBox7.Text = "物品損壞通知";
+ this.cgLogListenerCheckBox7.UseVisualStyleBackColor = true;
+ //
+ // chkCookingReminder
+ //
+ this.chkCookingReminder.AutoSize = true;
+ this.chkCookingReminder.Location = new System.Drawing.Point(1, 205);
+ this.chkCookingReminder.Name = "chkCookingReminder";
+ this.chkCookingReminder.Size = new System.Drawing.Size(104, 19);
+ this.chkCookingReminder.TabIndex = 15;
+ this.chkCookingReminder.Text = "計時器通知";
+ this.chkCookingReminder.UseVisualStyleBackColor = true;
+ this.chkCookingReminder.CheckedChanged += new System.EventHandler(this.ChkCookingReminder_CheckedChanged);
+ //
+ // txtCookingInterval
+ //
+ this.txtCookingInterval.Location = new System.Drawing.Point(109, 203);
+ this.txtCookingInterval.Name = "txtCookingInterval";
+ this.txtCookingInterval.Size = new System.Drawing.Size(40, 25);
+ this.txtCookingInterval.TabIndex = 16;
+ this.txtCookingInterval.Text = "180";
+ this.txtCookingInterval.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
+ this.txtCookingInterval.TextChanged += new System.EventHandler(this.txtCookingInterval_TextChanged);
+ //
+ // lblCookingUnit
+ //
+ this.lblCookingUnit.AutoSize = true;
+ this.lblCookingUnit.Location = new System.Drawing.Point(155, 206);
+ this.lblCookingUnit.Name = "lblCookingUnit";
+ this.lblCookingUnit.Size = new System.Drawing.Size(22, 15);
+ this.lblCookingUnit.TabIndex = 17;
+ this.lblCookingUnit.Text = "秒";
+ //
+ // txtCookingPattern
+ //
+ this.txtCookingPattern.Location = new System.Drawing.Point(1, 230);
+ this.txtCookingPattern.Name = "txtCookingPattern";
+ this.txtCookingPattern.Size = new System.Drawing.Size(254, 25);
+ this.txtCookingPattern.TabIndex = 19;
+ this.txtCookingPattern.Text = "恢復了\\d+魔力";
+ //
+ // txtCookingMessage
+ //
+ this.txtCookingMessage.Location = new System.Drawing.Point(2, 261);
+ this.txtCookingMessage.Name = "txtCookingMessage";
+ this.txtCookingMessage.Size = new System.Drawing.Size(200, 25);
+ this.txtCookingMessage.TabIndex = 20;
+ this.txtCookingMessage.Text = "時間到了,吃料理~";
+ //
+ // btnCookingDefault
+ //
+ this.btnCookingDefault.Location = new System.Drawing.Point(205, 264);
+ this.btnCookingDefault.Name = "btnCookingDefault";
+ this.btnCookingDefault.Size = new System.Drawing.Size(50, 22);
+ this.btnCookingDefault.TabIndex = 21;
+ this.btnCookingDefault.Text = "預設";
+ this.btnCookingDefault.UseVisualStyleBackColor = true;
+ this.btnCookingDefault.Click += new System.EventHandler(this.BtnCookingDefault_Click);
//
// cgLogListenerTrackBar
//
this.cgLogListenerTrackBar.AutoSize = false;
this.cgLogListenerTrackBar.LargeChange = 1;
- this.cgLogListenerTrackBar.Location = new System.Drawing.Point(2, 197);
+ this.cgLogListenerTrackBar.Location = new System.Drawing.Point(50, 172);
this.cgLogListenerTrackBar.Name = "cgLogListenerTrackBar";
this.cgLogListenerTrackBar.NameInSetting = "SoundVol";
- this.cgLogListenerTrackBar.Size = new System.Drawing.Size(108, 27);
+ this.cgLogListenerTrackBar.Size = new System.Drawing.Size(70, 27);
this.cgLogListenerTrackBar.TabIndex = 12;
this.cgLogListenerTrackBar.Value = 5;
//
- // cgLogListenerSettingCheckBox1
+ // lblSoundVol
//
- this.cgLogListenerSettingCheckBox1.AutoSize = true;
- this.cgLogListenerSettingCheckBox1.Location = new System.Drawing.Point(2, 172);
- this.cgLogListenerSettingCheckBox1.Name = "cgLogListenerSettingCheckBox1";
- this.cgLogListenerSettingCheckBox1.NameInSetting = "PlaySound";
- this.cgLogListenerSettingCheckBox1.RegexPattern = null;
- this.cgLogListenerSettingCheckBox1.Size = new System.Drawing.Size(72, 16);
- this.cgLogListenerSettingCheckBox1.TabIndex = 8;
- this.cgLogListenerSettingCheckBox1.Text = "播放音效";
- this.cgLogListenerSettingCheckBox1.UseVisualStyleBackColor = true;
+ this.lblSoundVol.AutoSize = true;
+ this.lblSoundVol.Location = new System.Drawing.Point(2, 177);
+ this.lblSoundVol.Name = "lblSoundVol";
+ this.lblSoundVol.Size = new System.Drawing.Size(52, 15);
+ this.lblSoundVol.TabIndex = 14;
+ this.lblSoundVol.Text = "音量:";
//
// cgLogListenerCheckBox6
//
this.cgLogListenerCheckBox6.AutoSize = true;
this.cgLogListenerCheckBox6.Location = new System.Drawing.Point(2, 124);
this.cgLogListenerCheckBox6.Name = "cgLogListenerCheckBox6";
- this.cgLogListenerCheckBox6.NameInSetting = "ReMaze";
+ this.cgLogListenerCheckBox6.NameInSetting = "6";
this.cgLogListenerCheckBox6.RegexPattern = "你感覺到一股不可思議的力量,而『.*』好像快(要?)消失了。";
- this.cgLogListenerCheckBox6.Size = new System.Drawing.Size(96, 16);
+ this.cgLogListenerCheckBox6.Size = new System.Drawing.Size(119, 19);
this.cgLogListenerCheckBox6.TabIndex = 8;
this.cgLogListenerCheckBox6.Text = "迷宮重組通知";
this.cgLogListenerCheckBox6.UseVisualStyleBackColor = true;
@@ -197,9 +299,9 @@ private void InitializeComponent()
this.cgLogListenerCheckBox5.AutoSize = true;
this.cgLogListenerCheckBox5.Location = new System.Drawing.Point(2, 99);
this.cgLogListenerCheckBox5.Name = "cgLogListenerCheckBox5";
- this.cgLogListenerCheckBox5.NameInSetting = "Sell";
+ this.cgLogListenerCheckBox5.NameInSetting = "5";
this.cgLogListenerCheckBox5.RegexPattern = "您順利賣掉了一個.*,(收入|獲得).*魔幣!";
- this.cgLogListenerCheckBox5.Size = new System.Drawing.Size(96, 16);
+ this.cgLogListenerCheckBox5.Size = new System.Drawing.Size(119, 19);
this.cgLogListenerCheckBox5.TabIndex = 8;
this.cgLogListenerCheckBox5.Text = "擺攤售出通知";
this.cgLogListenerCheckBox5.UseVisualStyleBackColor = true;
@@ -209,9 +311,9 @@ private void InitializeComponent()
this.cgLogListenerCheckBox4.AutoSize = true;
this.cgLogListenerCheckBox4.Location = new System.Drawing.Point(2, 74);
this.cgLogListenerCheckBox4.Name = "cgLogListenerCheckBox4";
- this.cgLogListenerCheckBox4.NameInSetting = "PlayerJoin";
+ this.cgLogListenerCheckBox4.NameInSetting = "4";
this.cgLogListenerCheckBox4.RegexPattern = "加入了(你|您)的隊伍。";
- this.cgLogListenerCheckBox4.Size = new System.Drawing.Size(108, 16);
+ this.cgLogListenerCheckBox4.Size = new System.Drawing.Size(134, 19);
this.cgLogListenerCheckBox4.TabIndex = 8;
this.cgLogListenerCheckBox4.Text = "被加入隊伍通知";
this.cgLogListenerCheckBox4.UseVisualStyleBackColor = true;
@@ -221,47 +323,63 @@ private void InitializeComponent()
this.cgLogListenerCheckBox3.AutoSize = true;
this.cgLogListenerCheckBox3.Location = new System.Drawing.Point(2, 49);
this.cgLogListenerCheckBox3.Name = "cgLogListenerCheckBox3";
- this.cgLogListenerCheckBox3.NameInSetting = "MP0";
+ this.cgLogListenerCheckBox3.NameInSetting = "3";
this.cgLogListenerCheckBox3.RegexPattern = "魔力不足。";
- this.cgLogListenerCheckBox3.Size = new System.Drawing.Size(96, 16);
+ this.cgLogListenerCheckBox3.Size = new System.Drawing.Size(119, 19);
this.cgLogListenerCheckBox3.TabIndex = 8;
this.cgLogListenerCheckBox3.Text = "魔力不足通知";
this.cgLogListenerCheckBox3.UseVisualStyleBackColor = true;
//
// label1
//
+ this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.label1.AutoSize = true;
- this.label1.Location = new System.Drawing.Point(126, 2);
+ this.label1.Location = new System.Drawing.Point(275, 2);
this.label1.Name = "label1";
- this.label1.Size = new System.Drawing.Size(65, 12);
+ this.label1.Size = new System.Drawing.Size(82, 15);
this.label1.TabIndex = 11;
this.label1.Text = "自訂關鍵字";
//
// cgLogListenerListBox
//
+ this.cgLogListenerListBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.cgLogListenerListBox.FormattingEnabled = true;
- this.cgLogListenerListBox.ItemHeight = 12;
- this.cgLogListenerListBox.Location = new System.Drawing.Point(127, 20);
+ this.cgLogListenerListBox.ItemHeight = 15;
+ this.cgLogListenerListBox.Location = new System.Drawing.Point(275, 20);
this.cgLogListenerListBox.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
this.cgLogListenerListBox.Name = "cgLogListenerListBox";
this.cgLogListenerListBox.NotifyIcon = this.notifyIcon;
- this.cgLogListenerListBox.Size = new System.Drawing.Size(147, 148);
+ this.cgLogListenerListBox.Size = new System.Drawing.Size(147, 169);
this.cgLogListenerListBox.TabIndex = 9;
//
// btnDelCus
- //
- this.btnDelCus.Location = new System.Drawing.Point(178, 181);
+ //
+ this.btnDelCus.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.btnDelCus.Location = new System.Drawing.Point(371, 194);
this.btnDelCus.Margin = new System.Windows.Forms.Padding(2);
this.btnDelCus.Name = "btnDelCus";
this.btnDelCus.Size = new System.Drawing.Size(47, 22);
- this.btnDelCus.TabIndex = 10;
+ this.btnDelCus.TabIndex = 11;
this.btnDelCus.Text = "移除";
this.btnDelCus.UseVisualStyleBackColor = true;
this.btnDelCus.Click += new System.EventHandler(this.BtnDelCus_Click);
- //
+ //
+ // btnEditCus
+ //
+ this.btnEditCus.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.btnEditCus.Location = new System.Drawing.Point(323, 194);
+ this.btnEditCus.Margin = new System.Windows.Forms.Padding(2);
+ this.btnEditCus.Name = "btnEditCus";
+ this.btnEditCus.Size = new System.Drawing.Size(47, 22);
+ this.btnEditCus.TabIndex = 10;
+ this.btnEditCus.Text = "修改";
+ this.btnEditCus.UseVisualStyleBackColor = true;
+ this.btnEditCus.Click += new System.EventHandler(this.BtnEditCus_Click);
+ //
// btnAddCus
//
- this.btnAddCus.Location = new System.Drawing.Point(127, 181);
+ this.btnAddCus.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.btnAddCus.Location = new System.Drawing.Point(275, 194);
this.btnAddCus.Margin = new System.Windows.Forms.Padding(2);
this.btnAddCus.Name = "btnAddCus";
this.btnAddCus.Size = new System.Drawing.Size(47, 22);
@@ -276,9 +394,9 @@ private void InitializeComponent()
this.cgLogListenerCheckBox2.Location = new System.Drawing.Point(2, 25);
this.cgLogListenerCheckBox2.Margin = new System.Windows.Forms.Padding(2);
this.cgLogListenerCheckBox2.Name = "cgLogListenerCheckBox2";
- this.cgLogListenerCheckBox2.NameInSetting = "ItemFull";
+ this.cgLogListenerCheckBox2.NameInSetting = "2";
this.cgLogListenerCheckBox2.RegexPattern = "物品欄沒有空位。";
- this.cgLogListenerCheckBox2.Size = new System.Drawing.Size(84, 16);
+ this.cgLogListenerCheckBox2.Size = new System.Drawing.Size(104, 19);
this.cgLogListenerCheckBox2.TabIndex = 1;
this.cgLogListenerCheckBox2.Text = "道具滿通知";
this.cgLogListenerCheckBox2.UseVisualStyleBackColor = true;
@@ -289,17 +407,66 @@ private void InitializeComponent()
this.cgLogListenerCheckBox1.Location = new System.Drawing.Point(2, 2);
this.cgLogListenerCheckBox1.Margin = new System.Windows.Forms.Padding(2);
this.cgLogListenerCheckBox1.Name = "cgLogListenerCheckBox1";
- this.cgLogListenerCheckBox1.NameInSetting = "Health";
+ this.cgLogListenerCheckBox1.NameInSetting = "1";
this.cgLogListenerCheckBox1.RegexPattern = "在工作時不小心受傷了。";
- this.cgLogListenerCheckBox1.Size = new System.Drawing.Size(96, 16);
+ this.cgLogListenerCheckBox1.Size = new System.Drawing.Size(119, 19);
this.cgLogListenerCheckBox1.TabIndex = 1;
this.cgLogListenerCheckBox1.Text = "採集受傷通知";
this.cgLogListenerCheckBox1.UseVisualStyleBackColor = true;
//
+ // txtCustomNotifier
+ //
+ this.txtCustomNotifier.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.txtCustomNotifier.Location = new System.Drawing.Point(132, 39);
+ this.txtCustomNotifier.Margin = new System.Windows.Forms.Padding(2);
+ this.txtCustomNotifier.Name = "txtCustomNotifier";
+ this.txtCustomNotifier.Size = new System.Drawing.Size(254, 25);
+ this.txtCustomNotifier.TabIndex = 13;
+ this.txtCustomNotifier.Leave += new System.EventHandler(this.TxtCustomNotifier_Leave);
+ //
+ // lblCustomNotifier
+ //
+ this.lblCustomNotifier.AutoSize = true;
+ this.lblCustomNotifier.Location = new System.Drawing.Point(11, 42);
+ this.lblCustomNotifier.Name = "lblCustomNotifier";
+ this.lblCustomNotifier.Size = new System.Drawing.Size(116, 15);
+ this.lblCustomNotifier.TabIndex = 22;
+ this.lblCustomNotifier.Text = "自定義通知路徑:";
+ //
+ // btnSelectNotifier
+ //
+ this.btnSelectNotifier.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.btnSelectNotifier.Location = new System.Drawing.Point(390, 38);
+ this.btnSelectNotifier.Margin = new System.Windows.Forms.Padding(2);
+ this.btnSelectNotifier.Name = "btnSelectNotifier";
+ this.btnSelectNotifier.Size = new System.Drawing.Size(53, 22);
+ this.btnSelectNotifier.TabIndex = 23;
+ this.btnSelectNotifier.Text = "選擇";
+ this.btnSelectNotifier.UseVisualStyleBackColor = true;
+ this.btnSelectNotifier.Click += new System.EventHandler(this.BtnSelectNotifier_Click);
+ //
+ // timerCooking
+ //
+ this.timerCooking.Interval = 180000;
+ this.timerCooking.Tick += new System.EventHandler(this.TimerCooking_Tick);
+ //
+ // btnSaveAppName
+ //
+ this.btnSaveAppName.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.btnSaveAppName.Location = new System.Drawing.Point(390, 68);
+ this.btnSaveAppName.Margin = new System.Windows.Forms.Padding(2);
+ this.btnSaveAppName.Name = "btnSaveAppName";
+ this.btnSaveAppName.Size = new System.Drawing.Size(53, 22);
+ this.btnSaveAppName.TabIndex = 22;
+ this.btnSaveAppName.Text = "儲存";
+ this.btnSaveAppName.UseVisualStyleBackColor = true;
+ this.btnSaveAppName.Click += new System.EventHandler(this.BtnSaveAppName_Click);
+ //
// btnExit
//
- this.btnExit.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
- this.btnExit.Location = new System.Drawing.Point(198, 300);
+ this.btnExit.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+ this.btnExit.Location = new System.Drawing.Point(355, 335);
this.btnExit.Margin = new System.Windows.Forms.Padding(2);
this.btnExit.Name = "btnExit";
this.btnExit.Size = new System.Drawing.Size(89, 22);
@@ -310,10 +477,11 @@ private void InitializeComponent()
//
// linkLabel1
//
+ this.linkLabel1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.linkLabel1.AutoSize = true;
- this.linkLabel1.Location = new System.Drawing.Point(9, 311);
+ this.linkLabel1.Location = new System.Drawing.Point(8, 391);
this.linkLabel1.Name = "linkLabel1";
- this.linkLabel1.Size = new System.Drawing.Size(65, 12);
+ this.linkLabel1.Size = new System.Drawing.Size(82, 15);
this.linkLabel1.TabIndex = 7;
this.linkLabel1.TabStop = true;
this.linkLabel1.Text = "關於本程式";
@@ -321,18 +489,23 @@ private void InitializeComponent()
//
// FormMain
//
- this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
+ this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
- this.ClientSize = new System.Drawing.Size(298, 333);
+ this.ClientSize = new System.Drawing.Size(455, 415);
this.Controls.Add(this.linkLabel1);
this.Controls.Add(this.panel1);
+ this.Controls.Add(this.lblAppName);
+ this.Controls.Add(this.btnSaveAppName);
+ this.Controls.Add(this.txtAppName);
this.Controls.Add(this.btnSelectLogPath);
this.Controls.Add(this.txtCgLogPath);
+ this.Controls.Add(this.txtCustomNotifier);
+ this.Controls.Add(this.lblCustomNotifier);
+ this.Controls.Add(this.btnSelectNotifier);
this.Controls.Add(this.btnExit);
this.Font = new System.Drawing.Font("新細明體", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3);
- this.MaximizeBox = false;
+ this.MinimumSize = new System.Drawing.Size(360, 325);
this.Name = "FormMain";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "魔力Log監視";
@@ -354,8 +527,11 @@ private void InitializeComponent()
private System.Windows.Forms.NotifyIcon notifyIcon;
private System.Windows.Forms.TextBox txtCgLogPath;
private System.Windows.Forms.Button btnSelectLogPath;
+ private System.Windows.Forms.Label lblAppName;
+ private System.Windows.Forms.TextBox txtAppName;
private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.Button btnDelCus;
+ private System.Windows.Forms.Button btnEditCus;
private System.Windows.Forms.Button btnAddCus;
private System.Windows.Forms.Button btnExit;
private System.Windows.Forms.ContextMenuStrip notifyIconContextMenu;
@@ -371,10 +547,20 @@ private void InitializeComponent()
private CgLogListenerCheckBox cgLogListenerCheckBox4;
private CgLogListenerCheckBox cgLogListenerCheckBox5;
private System.Windows.Forms.LinkLabel linkLabel1;
- private CgLogListenerCheckBox cgLogListenerSettingCheckBox1;
private CgLogListenerCheckBox cgLogListenerCheckBox6;
private CgLogListenerTrackBar cgLogListenerTrackBar;
- private System.Windows.Forms.CheckBox checkBox1;
+ private System.Windows.Forms.TextBox txtCustomNotifier;
+ private System.Windows.Forms.Label lblCustomNotifier;
+ private System.Windows.Forms.Button btnSelectNotifier;
+ private System.Windows.Forms.Label lblSoundVol;
+ private System.Windows.Forms.CheckBox chkCookingReminder;
+ private System.Windows.Forms.TextBox txtCookingInterval;
+ private System.Windows.Forms.Label lblCookingUnit;
+ private System.Windows.Forms.TextBox txtCookingPattern;
+ private System.Windows.Forms.TextBox txtCookingMessage;
+ private System.Windows.Forms.Button btnCookingDefault;
+ private System.Windows.Forms.Timer timerCooking;
+ private CgLogListenerCheckBox cgLogListenerCheckBox7;
+ private System.Windows.Forms.Button btnSaveAppName;
}
}
-
diff --git a/src/CgLogListener/FormMain.cs b/src/CgLogListener/FormMain.cs
index cecb49b..26016e6 100644
--- a/src/CgLogListener/FormMain.cs
+++ b/src/CgLogListener/FormMain.cs
@@ -1,7 +1,10 @@
-using System;
+using System;
+using System.Collections.Generic;
using System.Diagnostics;
+using System.Drawing;
using System.IO;
using System.Linq;
+using System.Text.RegularExpressions;
using System.Web;
using System.Windows.Forms;
using System.Windows.Media;
@@ -13,6 +16,9 @@ public partial class FormMain : Form
private Settings settings;
private CgLogHandler watcher;
private readonly MediaPlayer mp = new MediaPlayer();
+ private readonly Dictionary soundCheckBoxes = new Dictionary();
+ private readonly Dictionary mailCheckBoxes = new Dictionary();
+ private readonly Dictionary customNotifyCheckBoxes = new Dictionary();
public FormMain()
{
@@ -28,6 +34,10 @@ private void FrmMain_Load(object sender, EventArgs e)
{
settings = Settings.GetInstance();
+ // 設定通知標題
+ txtAppName.Text = settings.AppName;
+ UpdateAppTitle();
+
if (string.IsNullOrEmpty(settings.CgLogPath))
{
string cgLogPath = settings.CgLogPath;
@@ -43,7 +53,6 @@ private void FrmMain_Load(object sender, EventArgs e)
if (!Directory.Exists(settings.CgLogPath) || !CgLogHandler.ValidationPath(settings.CgLogPath))
{
- // the dir path invalid, set to default and exit
settings.SetCgLogPath(string.Empty);
MessageBox.Show(this, "設定檔路徑錯誤, 請重新啟動", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
this.Close();
@@ -52,56 +61,153 @@ private void FrmMain_Load(object sender, EventArgs e)
BindWatcher();
- // set playsound check
- cgLogListenerSettingCheckBox1.Checked = settings.PlaySound;
-
// set playsound vol
cgLogListenerTrackBar.Value = settings.SoundVol;
- // set line notify
- checkBox1.Checked = settings.CustomNotify;
+ // set custom notifier path
+ txtCustomNotifier.Text = settings.CustomNotifier ?? "";
- // set default tips check
- foreach (var chk in panel1.Controls.OfType())
- {
- // skip playsound
- if (chk == cgLogListenerSettingCheckBox1) { continue; }
+ // 設定標準關鍵字及其音效/郵件選項
+ SetupStandardTips();
- settings.StandardTips.TryGetValue(chk.NameInSetting, out bool isEnable);
- chk.Checked = isEnable;
- }
+ // 設定自訂關鍵字
+ SetupCustomTips();
- // set custom tips items
- settings.CustomizeTips
- .ForEach(s =>
- {
- if (!string.IsNullOrEmpty(s))
- {
- cgLogListenerListBox.Items.Add(s);
- }
- });
-
- cgLogListenerCheckBox1.CheckedChanged += CgLogListenerCheckBox_CheckedChanged;
- cgLogListenerCheckBox2.CheckedChanged += CgLogListenerCheckBox_CheckedChanged;
- cgLogListenerCheckBox3.CheckedChanged += CgLogListenerCheckBox_CheckedChanged;
- cgLogListenerCheckBox4.CheckedChanged += CgLogListenerCheckBox_CheckedChanged;
- cgLogListenerCheckBox5.CheckedChanged += CgLogListenerCheckBox_CheckedChanged;
- cgLogListenerCheckBox6.CheckedChanged += CgLogListenerCheckBox_CheckedChanged;
- cgLogListenerSettingCheckBox1.CheckedChanged += CgLogListenerSettingCheckBox1_CheckedChanged;
cgLogListenerTrackBar.ValueChanged += CgLogListenerTrackBar_ValueChanged;
- checkBox1.CheckedChanged += CheckBox1_CheckedChanged;
+ txtCustomNotifier.Leave += TxtCustomNotifier_Leave;
}
- private void CgLogListenerCheckBox_CheckedChanged(object sender, EventArgs e)
+ private void SetupStandardTips()
{
- var chk = (CgLogListenerCheckBox)sender;
- settings.SetStandardTip(chk.NameInSetting, chk.Checked);
+ var standardCheckBoxes = new[]
+ {
+ cgLogListenerCheckBox1,
+ cgLogListenerCheckBox2,
+ cgLogListenerCheckBox3,
+ cgLogListenerCheckBox4,
+ cgLogListenerCheckBox5,
+ cgLogListenerCheckBox6,
+ cgLogListenerCheckBox7
+ };
+
+ // 固定位置讓 S/M/C checkbox 對齊
+ const int soundCheckBoxX = 155;
+ const int mailCheckBoxX = 210;
+ const int customNotifyCheckBoxX = 265;
+
+ foreach (var chk in standardCheckBoxes)
+ {
+ var nameInSetting = chk.NameInSetting;
+
+ // 取得或建立設定
+ if (!settings.StandardTips.TryGetValue(nameInSetting, out TipNotifyOptions options))
+ {
+ options = new TipNotifyOptions();
+ settings.SetStandardTip(nameInSetting, options);
+ }
+
+ // 從 settings 讀取 Text 和 RegexPattern(如果有的話,否則使用 Designer 的預設值)
+ if (!string.IsNullOrEmpty(options.Text))
+ {
+ chk.Text = options.Text;
+ }
+ else
+ {
+ // 回寫 Designer 的預設值到 settings,方便使用者編輯 settings.ini
+ options.Text = chk.Text;
+ }
+
+ if (!string.IsNullOrEmpty(options.RegexPattern))
+ {
+ chk.RegexPattern = options.RegexPattern;
+ }
+ else
+ {
+ // 回寫 Designer 的預設值到 settings,方便使用者編輯 settings.ini
+ options.RegexPattern = chk.RegexPattern;
+ }
+
+ // 儲存更新後的設定(確保 Text 和 RegexPattern 被寫入 settings.ini)
+ settings.SetStandardTip(nameInSetting, options);
+
+ // 設定主 checkbox
+ chk.Checked = options.Enabled;
+ chk.AutoSize = false;
+ chk.Width = 150; // 限制寬度,避免長文字蓋掉右邊的 🔊 ✉ C (主 checkbox X=2,🔊 X=155,可用空間 153px)
+ chk.CheckedChanged += (s, ev) =>
+ {
+ var cb = (CgLogListenerCheckBox)s;
+ settings.SetStandardTipEnabled(cb.NameInSetting, cb.Checked);
+ };
+
+ // 動態建立音效 checkbox
+ var soundChk = new CheckBox
+ {
+ Text = "🔊",
+ AutoSize = true,
+ Location = new Point(soundCheckBoxX, chk.Top),
+ Checked = options.PlaySound,
+ Font = new Font("Segoe UI Emoji", 8)
+ };
+ soundChk.CheckedChanged += (s, ev) =>
+ {
+ settings.SetStandardTipPlaySound(nameInSetting, ((CheckBox)s).Checked);
+ };
+ panel1.Controls.Add(soundChk);
+ soundCheckBoxes[nameInSetting] = soundChk;
+
+ // 動態建立郵件 checkbox
+ var mailChk = new CheckBox
+ {
+ Text = "✉",
+ AutoSize = true,
+ Location = new Point(mailCheckBoxX, chk.Top),
+ Checked = options.SendMail,
+ Font = new Font("Segoe UI Emoji", 8)
+ };
+ mailChk.CheckedChanged += (s, ev) =>
+ {
+ var isChecked = ((CheckBox)s).Checked;
+ if (isChecked && !MailHelper.IsConfigured())
+ {
+ MailHelper.GenerateDefaultConfig();
+ MessageBox.Show(this, "請先設定 mail.ini 檔案中的 SMTP 資訊", "郵件設定", MessageBoxButtons.OK, MessageBoxIcon.Information);
+ }
+ settings.SetStandardTipSendMail(nameInSetting, isChecked);
+ };
+ panel1.Controls.Add(mailChk);
+ mailCheckBoxes[nameInSetting] = mailChk;
+
+ // 動態建立 CustomNotify checkbox
+ var customNotifyChk = new CheckBox
+ {
+ Text = "C",
+ AutoSize = true,
+ Location = new Point(customNotifyCheckBoxX, chk.Top),
+ Checked = options.CustomNotify,
+ Font = new Font("微軟正黑體", 8)
+ };
+ customNotifyChk.CheckedChanged += (s, ev) =>
+ {
+ settings.SetStandardTipCustomNotify(nameInSetting, ((CheckBox)s).Checked);
+ };
+ panel1.Controls.Add(customNotifyChk);
+ customNotifyCheckBoxes[nameInSetting] = customNotifyChk;
+ }
}
- private void CgLogListenerSettingCheckBox1_CheckedChanged(object sender, EventArgs e)
+ private void SetupCustomTips()
{
- var chk = (CgLogListenerCheckBox)sender;
- settings.SetPlaySound(chk.Checked);
+ foreach (var kv in settings.CustomizeTips)
+ {
+ if (!string.IsNullOrEmpty(kv.Key))
+ {
+ cgLogListenerListBox.Items.Add(kv.Key);
+ }
+ }
+
+ // 雙擊修改
+ cgLogListenerListBox.DoubleClick += (s, ev) => BtnEditCus_Click(s, ev);
}
private void CgLogListenerTrackBar_ValueChanged(object sender, EventArgs e)
@@ -158,16 +264,47 @@ void BindWatcher()
watcher.OnNewLog += Watcher_OnNewLog;
}
+ private const string DefaultCookingPattern = @"恢復了\d+魔力";
+ private const string DefaultCookingMessage = "時間到了,吃料理~";
+
void Watcher_OnNewLog(string log)
{
+ // 吃料理監聽:使用自定義 Regex pattern 偵測
+ var cookingPattern = string.IsNullOrWhiteSpace(txtCookingPattern.Text)
+ ? DefaultCookingPattern
+ : txtCookingPattern.Text;
+
+ bool cookingMatch = false;
+ try
+ {
+ cookingMatch = chkCookingReminder.Checked && Regex.IsMatch(log, cookingPattern);
+ }
+ catch { }
+
+ if (cookingMatch)
+ {
+ Invoke((Action)delegate
+ {
+ // 重置計時器
+ timerCooking.Stop();
+ if (int.TryParse(txtCookingInterval.Text, out int seconds) && seconds > 0)
+ {
+ timerCooking.Interval = seconds * 1000;
+ timerCooking.Start();
+ }
+ });
+ }
+
foreach (var n in panel1.Controls.OfType())
{
- if (n.Notify(log))
+ var result = n.Notify(log);
+ if (result.IsMatch)
{
notifyIcon.ShowBalloonTip(1, notifyIcon.BalloonTipTitle, log, ToolTipIcon.None);
+ // 根據該關鍵字的設定決定是否播放音效
const string soundName = "sound.wav";
- if (settings.PlaySound && File.Exists(soundName))
+ if (result.PlaySound && File.Exists(soundName))
{
Invoke((Action)delegate
{
@@ -178,13 +315,27 @@ void Watcher_OnNewLog(string log)
});
}
- if (settings.CustomNotify)
+ // 根據該關鍵字的設定決定是否發送郵件
+ if (result.SendMail)
+ {
+ try
+ {
+ MailHelper.SendMail("魔力Log監視通知", log);
+ }
+ catch { }
+ }
+
+ // Custom Notifier (根據個別關鍵字設定)
+ if (result.CustomNotify && !string.IsNullOrEmpty(settings.CustomNotifier))
{
foreach (var notifier in settings.CustomNotifier.Split(','))
{
+ var trimmedNotifier = notifier.Trim();
+ if (string.IsNullOrEmpty(trimmedNotifier)) continue;
+
try
{
- ProcessStartInfo p = new ProcessStartInfo(notifier, $"\"{log}\"")
+ ProcessStartInfo p = new ProcessStartInfo(trimmedNotifier, $"\"[{settings.AppName}] {log}\"")
{
WindowStyle = ProcessWindowStyle.Hidden,
CreateNoWindow = true
@@ -195,7 +346,6 @@ void Watcher_OnNewLog(string log)
}
}
- // break if was trigger
break;
}
}
@@ -203,16 +353,43 @@ void Watcher_OnNewLog(string log)
private void BtnAddCus_Click(object sender, EventArgs e)
{
- if (FormPrompt.ShowDialog(this, out string value) != DialogResult.OK ||
+ if (FormPrompt.ShowDialog(this, out string value, out TipNotifyOptions options) != DialogResult.OK ||
string.IsNullOrEmpty(value))
{
return;
}
- settings.AddCustmizeTip(value);
+ settings.AddCustomizeTip(value, options);
cgLogListenerListBox.Items.Add(value);
}
+ private void BtnEditCus_Click(object sender, EventArgs e)
+ {
+ if (cgLogListenerListBox.SelectedIndex < 0)
+ {
+ MessageBox.Show(this, "請先選擇要修改的關鍵字", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
+ return;
+ }
+
+ var oldKeyword = (string)cgLogListenerListBox.SelectedItem;
+ var oldOptions = settings.CustomizeTips[oldKeyword];
+
+ if (FormPrompt.ShowDialogForEdit(this, oldKeyword, oldOptions, out string newKeyword, out TipNotifyOptions newOptions) != DialogResult.OK ||
+ string.IsNullOrEmpty(newKeyword))
+ {
+ return;
+ }
+
+ // 刪除舊的
+ settings.RemoveCustomizeTip(oldKeyword);
+ cgLogListenerListBox.Items.Remove(oldKeyword);
+
+ // 加入新的
+ settings.AddCustomizeTip(newKeyword, newOptions);
+ cgLogListenerListBox.Items.Add(newKeyword);
+ cgLogListenerListBox.SelectedItem = newKeyword;
+ }
+
private void BtnDelCus_Click(object sender, EventArgs e)
{
if (cgLogListenerListBox.SelectedIndex < 0)
@@ -221,22 +398,120 @@ private void BtnDelCus_Click(object sender, EventArgs e)
}
var selectItem = (string)cgLogListenerListBox.SelectedItem;
- settings.RemoveCustmizeTip(selectItem);
+ settings.RemoveCustomizeTip(selectItem);
cgLogListenerListBox.Items.Remove(selectItem);
}
- private void CheckBox1_CheckedChanged(object sender, EventArgs e)
+ private void TxtCustomNotifier_Leave(object sender, EventArgs e)
+ {
+ settings.SetCustomNotifier(txtCustomNotifier.Text);
+ }
+
+ private void BtnSelectNotifier_Click(object sender, EventArgs e)
+ {
+ var dialog = new OpenFileDialog
+ {
+ Filter = "執行檔 (*.exe)|*.exe|所有檔案 (*.*)|*.*",
+ Title = "選擇 Notifier 程式"
+ };
+
+ if (dialog.ShowDialog(this) == DialogResult.OK)
+ {
+ var currentPaths = txtCustomNotifier.Text;
+ if (string.IsNullOrEmpty(currentPaths))
+ {
+ txtCustomNotifier.Text = dialog.FileName;
+ }
+ else
+ {
+ txtCustomNotifier.Text = currentPaths + "," + dialog.FileName;
+ }
+ settings.SetCustomNotifier(txtCustomNotifier.Text);
+ }
+ }
+
+ private void TxtAppName_Leave(object sender, EventArgs e)
+ {
+ // 不再自動儲存,由按鈕觸發
+ }
+
+ private void BtnSaveAppName_Click(object sender, EventArgs e)
+ {
+ var newAppName = txtAppName.Text.Trim();
+ if (string.IsNullOrEmpty(newAppName))
+ {
+ newAppName = "CgLogListener";
+ txtAppName.Text = newAppName;
+ }
+ settings.SetAppName(newAppName);
+ UpdateAppTitle();
+ }
+
+ private void UpdateAppTitle()
+ {
+ var appTitle = $"[{settings.AppName}] 魔力Log監視";
+ notifyIcon.BalloonTipTitle = appTitle;
+ notifyIcon.Text = appTitle;
+ this.Text = appTitle;
+ }
+
+ private void ChkCookingReminder_CheckedChanged(object sender, EventArgs e)
{
- if (checkBox1.Checked)
+ if (chkCookingReminder.Checked)
{
- FormCustomNotifierPrompt.ShowDialog(this, out string value);
- settings.SetCustomNotify(true);
- settings.SetCustomNotifier(value);
+ if (!int.TryParse(txtCookingInterval.Text, out int seconds) || seconds <= 0)
+ {
+ MessageBox.Show("請輸入有效的秒數", "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Warning);
+ chkCookingReminder.Checked = false;
+ return;
+ }
+
+ // 驗證 Regex pattern 是否有效
+ var pattern = string.IsNullOrWhiteSpace(txtCookingPattern.Text)
+ ? DefaultCookingPattern
+ : txtCookingPattern.Text;
+ try
+ {
+ Regex.IsMatch("test", pattern);
+ }
+ catch
+ {
+ MessageBox.Show("Regex 格式錯誤", "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Warning);
+ chkCookingReminder.Checked = false;
+ return;
+ }
}
else
{
- settings.SetCustomNotify(false);
- settings.SetCustomNotifier(string.Empty);
+ timerCooking.Stop();
+ }
+ }
+
+ private void BtnCookingDefault_Click(object sender, EventArgs e)
+ {
+ txtCookingPattern.Text = DefaultCookingPattern;
+ txtCookingMessage.Text = DefaultCookingMessage;
+ }
+
+ private void TimerCooking_Tick(object sender, EventArgs e)
+ {
+ var message = string.IsNullOrWhiteSpace(txtCookingMessage.Text)
+ ? DefaultCookingMessage
+ : txtCookingMessage.Text;
+
+ notifyIcon.ShowBalloonTip(3000, $"[{settings.AppName}] 吃料理通知", message, ToolTipIcon.Info);
+
+ // 播放音效
+ const string soundName = "sound.wav";
+ if (File.Exists(soundName))
+ {
+ Invoke((Action)delegate
+ {
+ mp.Stop();
+ mp.Open(new Uri(new FileInfo(soundName).FullName));
+ mp.Volume = settings.SoundVol / 10d;
+ mp.Play();
+ });
}
}
@@ -291,6 +566,13 @@ private void FormMain_Resize(object sender, EventArgs e)
private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
{
+ // 確保 AppName 在關閉前儲存
+ var newAppName = txtAppName.Text.Trim();
+ if (!string.IsNullOrEmpty(newAppName) && newAppName != settings.AppName)
+ {
+ settings.SetAppName(newAppName);
+ }
+
watcher?.Dispose();
notifyIcon?.Dispose();
}
@@ -301,5 +583,10 @@ private void LinkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs
{
System.Diagnostics.Process.Start("https://github.com/WindOfNet/CgLogListener");
}
+
+ private void txtCookingInterval_TextChanged(object sender, EventArgs e)
+ {
+
+ }
}
}
diff --git a/src/CgLogListener/FormMain.resx b/src/CgLogListener/FormMain.resx
index 789ad64..bb9c6d4 100644
--- a/src/CgLogListener/FormMain.resx
+++ b/src/CgLogListener/FormMain.resx
@@ -118,10 +118,10 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
- 17, 17
+ 173, 17
- 147, 17
+ 302, 17
@@ -148,4 +148,7 @@
AADgBwAA+B8AAA==
+
+ 17, 17
+
\ No newline at end of file
diff --git a/src/CgLogListener/FormPrompt.Designer.cs b/src/CgLogListener/FormPrompt.Designer.cs
index e57dc3b..36ea7ee 100644
--- a/src/CgLogListener/FormPrompt.Designer.cs
+++ b/src/CgLogListener/FormPrompt.Designer.cs
@@ -34,6 +34,11 @@ private void InitializeComponent()
this.btnCancel = new System.Windows.Forms.Button();
this.label2 = new System.Windows.Forms.Label();
this.txtExp = new System.Windows.Forms.TextBox();
+ this.chkEnabled = new System.Windows.Forms.CheckBox();
+ this.chkPlaySound = new System.Windows.Forms.CheckBox();
+ this.chkSendMail = new System.Windows.Forms.CheckBox();
+ this.chkIsRegex = new System.Windows.Forms.CheckBox();
+ this.chkCustomNotify = new System.Windows.Forms.CheckBox();
this.SuspendLayout();
//
// btnOk
@@ -88,15 +93,74 @@ private void InitializeComponent()
this.txtExp.Name = "txtExp";
this.txtExp.Size = new System.Drawing.Size(165, 21);
this.txtExp.TabIndex = 2;
- //
+ //
+ // chkEnabled
+ //
+ this.chkEnabled.AutoSize = true;
+ this.chkEnabled.Checked = true;
+ this.chkEnabled.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.chkEnabled.Location = new System.Drawing.Point(14, 61);
+ this.chkEnabled.Name = "chkEnabled";
+ this.chkEnabled.Size = new System.Drawing.Size(52, 19);
+ this.chkEnabled.TabIndex = 5;
+ this.chkEnabled.Text = "啟用";
+ this.chkEnabled.UseVisualStyleBackColor = true;
+ //
+ // chkPlaySound
+ //
+ this.chkPlaySound.AutoSize = true;
+ this.chkPlaySound.Checked = true;
+ this.chkPlaySound.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.chkPlaySound.Location = new System.Drawing.Point(72, 61);
+ this.chkPlaySound.Name = "chkPlaySound";
+ this.chkPlaySound.Size = new System.Drawing.Size(52, 19);
+ this.chkPlaySound.TabIndex = 6;
+ this.chkPlaySound.Text = "音效";
+ this.chkPlaySound.UseVisualStyleBackColor = true;
+ //
+ // chkSendMail
+ //
+ this.chkSendMail.AutoSize = true;
+ this.chkSendMail.Location = new System.Drawing.Point(130, 61);
+ this.chkSendMail.Name = "chkSendMail";
+ this.chkSendMail.Size = new System.Drawing.Size(52, 19);
+ this.chkSendMail.TabIndex = 7;
+ this.chkSendMail.Text = "寄信";
+ this.chkSendMail.UseVisualStyleBackColor = true;
+ //
+ // chkIsRegex
+ //
+ this.chkIsRegex.AutoSize = true;
+ this.chkIsRegex.Location = new System.Drawing.Point(188, 61);
+ this.chkIsRegex.Name = "chkIsRegex";
+ this.chkIsRegex.Size = new System.Drawing.Size(58, 19);
+ this.chkIsRegex.TabIndex = 8;
+ this.chkIsRegex.Text = "Regex";
+ this.chkIsRegex.UseVisualStyleBackColor = true;
+ //
+ // chkCustomNotify
+ //
+ this.chkCustomNotify.AutoSize = true;
+ this.chkCustomNotify.Location = new System.Drawing.Point(252, 61);
+ this.chkCustomNotify.Name = "chkCustomNotify";
+ this.chkCustomNotify.Size = new System.Drawing.Size(34, 19);
+ this.chkCustomNotify.TabIndex = 9;
+ this.chkCustomNotify.Text = "C";
+ this.chkCustomNotify.UseVisualStyleBackColor = true;
+ //
// FormPrompt
- //
+ //
this.AcceptButton = this.btnOk;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.btnCancel;
- this.ClientSize = new System.Drawing.Size(368, 64);
+ this.ClientSize = new System.Drawing.Size(368, 90);
this.ControlBox = false;
+ this.Controls.Add(this.chkCustomNotify);
+ this.Controls.Add(this.chkIsRegex);
+ this.Controls.Add(this.chkSendMail);
+ this.Controls.Add(this.chkPlaySound);
+ this.Controls.Add(this.chkEnabled);
this.Controls.Add(this.txtExp);
this.Controls.Add(this.label2);
this.Controls.Add(this.txtValue);
@@ -111,7 +175,7 @@ private void InitializeComponent()
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
- this.Text = " ";
+ this.Text = "新增/編輯自訂關鍵字";
this.ResumeLayout(false);
this.PerformLayout();
@@ -125,5 +189,10 @@ private void InitializeComponent()
private System.Windows.Forms.Button btnCancel;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.TextBox txtExp;
+ private System.Windows.Forms.CheckBox chkEnabled;
+ private System.Windows.Forms.CheckBox chkPlaySound;
+ private System.Windows.Forms.CheckBox chkSendMail;
+ private System.Windows.Forms.CheckBox chkIsRegex;
+ private System.Windows.Forms.CheckBox chkCustomNotify;
}
}
\ No newline at end of file
diff --git a/src/CgLogListener/FormPrompt.cs b/src/CgLogListener/FormPrompt.cs
index 8436e84..4be1eb8 100644
--- a/src/CgLogListener/FormPrompt.cs
+++ b/src/CgLogListener/FormPrompt.cs
@@ -18,6 +18,12 @@ public partial class FormPrompt : Form
}
public static DialogResult ShowDialog(IWin32Window owner, out string value)
+ {
+ var result = ShowDialog(owner, out value, out _);
+ return result;
+ }
+
+ public static DialogResult ShowDialog(IWin32Window owner, out string value, out TipNotifyOptions options)
{
FormPrompt f = new FormPrompt();
DialogResult result = f.ShowDialog(owner);
@@ -27,6 +33,55 @@ public static DialogResult ShowDialog(IWin32Window owner, out string value)
value += $"|{f.txtExp.Text}";
}
+ options = new TipNotifyOptions(
+ f.chkEnabled.Checked,
+ f.chkPlaySound.Checked,
+ f.chkSendMail.Checked,
+ f.chkIsRegex.Checked,
+ f.chkCustomNotify.Checked
+ );
+
+ return result;
+ }
+
+ ///
+ /// 編輯模式:預填已有的關鍵字和選項
+ ///
+ public static DialogResult ShowDialogForEdit(IWin32Window owner, string existingKeyword, TipNotifyOptions existingOptions, out string value, out TipNotifyOptions options)
+ {
+ FormPrompt f = new FormPrompt();
+ f.Text = "編輯自訂關鍵字";
+
+ // 解析 keyword 和排除詞
+ var split = existingKeyword.Split('|');
+ f.txtValue.Text = split[0];
+ if (split.Length > 1)
+ {
+ f.txtExp.Text = split[1];
+ }
+
+ // 預填選項
+ f.chkEnabled.Checked = existingOptions.Enabled;
+ f.chkPlaySound.Checked = existingOptions.PlaySound;
+ f.chkSendMail.Checked = existingOptions.SendMail;
+ f.chkIsRegex.Checked = existingOptions.IsRegex;
+ f.chkCustomNotify.Checked = existingOptions.CustomNotify;
+
+ DialogResult result = f.ShowDialog(owner);
+ value = f.txtValue.Text;
+ if (!string.IsNullOrWhiteSpace(f.txtExp.Text))
+ {
+ value += $"|{f.txtExp.Text}";
+ }
+
+ options = new TipNotifyOptions(
+ f.chkEnabled.Checked,
+ f.chkPlaySound.Checked,
+ f.chkSendMail.Checked,
+ f.chkIsRegex.Checked,
+ f.chkCustomNotify.Checked
+ );
+
return result;
}
diff --git a/src/CgLogListener/INotifyMessage.cs b/src/CgLogListener/INotifyMessage.cs
index ce139db..67ab6ee 100644
--- a/src/CgLogListener/INotifyMessage.cs
+++ b/src/CgLogListener/INotifyMessage.cs
@@ -7,6 +7,6 @@ namespace CgLogListener
{
public interface INotifyMessage
{
- bool Notify(string message);
+ NotifyResult Notify(string message);
}
}
diff --git a/src/CgLogListener/MailHelper.cs b/src/CgLogListener/MailHelper.cs
new file mode 100644
index 0000000..59cb411
--- /dev/null
+++ b/src/CgLogListener/MailHelper.cs
@@ -0,0 +1,116 @@
+using IniParser;
+using System;
+using System.IO;
+using System.Net;
+using System.Net.Mail;
+
+namespace CgLogListener
+{
+ public static class MailHelper
+ {
+ private const string MailConfigFileName = "mail.ini";
+
+ public static bool IsConfigured()
+ {
+ if (!File.Exists(MailConfigFileName))
+ {
+ return false;
+ }
+
+ try
+ {
+ var ini = new FileIniDataParser().ReadFile(MailConfigFileName);
+ return !string.IsNullOrEmpty(ini["smtp"]["host"]) &&
+ !string.IsNullOrEmpty(ini["smtp"]["from"]) &&
+ !string.IsNullOrEmpty(ini["smtp"]["to"]);
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+ public static void SendMail(string subject, string body)
+ {
+ if (!File.Exists(MailConfigFileName))
+ {
+ return;
+ }
+
+ try
+ {
+ var appName = Settings.GetInstance().AppName;
+ var fullSubject = $"[{appName}] {subject}";
+
+ var ini = new FileIniDataParser().ReadFile(MailConfigFileName);
+ var smtpSection = ini["smtp"];
+
+ var host = smtpSection["host"];
+ var portStr = smtpSection["port"];
+ var username = smtpSection["username"];
+ var password = smtpSection["password"];
+ var from = smtpSection["from"];
+ var to = smtpSection["to"];
+ var enableSslStr = smtpSection["enableSsl"];
+
+ if (string.IsNullOrEmpty(host) || string.IsNullOrEmpty(from) || string.IsNullOrEmpty(to))
+ {
+ return;
+ }
+
+ int port = 587;
+ if (!string.IsNullOrEmpty(portStr))
+ {
+ int.TryParse(portStr, out port);
+ }
+
+ bool enableSsl = true;
+ if (!string.IsNullOrEmpty(enableSslStr))
+ {
+ enableSsl = enableSslStr == "1" || enableSslStr.ToLower() == "true";
+ }
+
+ using (var client = new SmtpClient(host, port))
+ {
+ client.EnableSsl = enableSsl;
+
+ if (!string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password))
+ {
+ client.Credentials = new NetworkCredential(username, password);
+ }
+
+ var message = new MailMessage(from, to, fullSubject, body);
+ client.Send(message);
+ }
+ }
+ catch
+ {
+ // 發送失敗時靜默處理,避免影響主程式
+ }
+ }
+
+ public static void GenerateDefaultConfig()
+ {
+ if (File.Exists(MailConfigFileName))
+ {
+ return;
+ }
+
+ var content = @"[smtp]
+; SMTP 伺服器設定
+host=smtp.gmail.com
+port=587
+enableSsl=1
+
+; 認證資訊 (如果 SMTP 需要認證)
+username=
+password=
+
+; 寄件者與收件者
+from=your-email@gmail.com
+to=recipient@example.com
+";
+ File.WriteAllText(MailConfigFileName, content);
+ }
+ }
+}
diff --git a/src/CgLogListener/NotifyResult.cs b/src/CgLogListener/NotifyResult.cs
new file mode 100644
index 0000000..c401e7a
--- /dev/null
+++ b/src/CgLogListener/NotifyResult.cs
@@ -0,0 +1,23 @@
+namespace CgLogListener
+{
+ public class NotifyResult
+ {
+ public bool IsMatch { get; set; }
+ public bool PlaySound { get; set; }
+ public bool SendMail { get; set; }
+ public bool CustomNotify { get; set; }
+
+ public static NotifyResult NoMatch => new NotifyResult { IsMatch = false };
+
+ public static NotifyResult Match(bool playSound, bool sendMail, bool customNotify)
+ {
+ return new NotifyResult
+ {
+ IsMatch = true,
+ PlaySound = playSound,
+ SendMail = sendMail,
+ CustomNotify = customNotify
+ };
+ }
+ }
+}
diff --git a/src/CgLogListener/Settings.cs b/src/CgLogListener/Settings.cs
index ad0c2ec..400d12e 100644
--- a/src/CgLogListener/Settings.cs
+++ b/src/CgLogListener/Settings.cs
@@ -1,4 +1,4 @@
-using IniParser;
+using IniParser;
using IniParser.Model;
using System;
using System.Collections.Generic;
@@ -14,15 +14,15 @@ public sealed class Settings
const string settingsFileName = "settings.ini";
const string settingsBaseSection = "base";
const string settingsStandardTipsSection = "standard tips";
+ const string settingsCustomTipsSection = "custom tips";
const string custmizeFileName = "custmize.dat";
- public bool CustomNotify { get; private set; }
+ public string AppName { get; private set; }
public string CustomNotifier { get; private set; }
- public bool PlaySound { get; private set; }
public int SoundVol { get; private set; }
public string CgLogPath { get; private set; }
- public Dictionary StandardTips { get; private set; } = new Dictionary();
- public List CustomizeTips { get; private set; } = new List();
+ public Dictionary StandardTips { get; private set; } = new Dictionary();
+ public Dictionary CustomizeTips { get; private set; } = new Dictionary();
public static Settings GetInstance()
{
@@ -39,11 +39,9 @@ public void Load()
{
if (!File.Exists(Path.Combine(Directory.GetCurrentDirectory(), settingsFileName)))
{
- // gen new conf file
GenConfigFile();
}
- // load settings
LoadSettings();
}
@@ -53,24 +51,38 @@ private void LoadSettings()
var iniData = fileIniDataParser.ReadFile(settingsFileName);
var baseData = iniData[settingsBaseSection];
+ AppName = baseData[nameof(AppName)] ?? "CgLogListener";
+ if (string.IsNullOrEmpty(AppName)) AppName = "CgLogListener";
CgLogPath = baseData[nameof(CgLogPath)];
- PlaySound = baseData[nameof(PlaySound)] == "1";
- SoundVol = int.Parse(baseData[nameof(SoundVol)]);
- CustomNotify = baseData[nameof(CustomNotify)] == "1";
+ SoundVol = int.Parse(baseData[nameof(SoundVol)] ?? "5");
CustomNotifier = baseData[nameof(CustomNotifier)];
+ // 載入標準關鍵字設定
var standardTipData = iniData[settingsStandardTipsSection];
foreach (var kd in standardTipData)
{
- StandardTips.Add(kd.KeyName, kd.Value == "1");
+ StandardTips[kd.KeyName] = TipNotifyOptions.Parse(kd.Value);
}
+ // 載入自訂關鍵字設定
+ var customTipData = iniData[settingsCustomTipsSection];
+ foreach (var kd in customTipData)
+ {
+ CustomizeTips[kd.KeyName] = TipNotifyOptions.Parse(kd.Value);
+ }
+
+ // 相容舊版:讀取舊的 custmize.dat
if (File.Exists(custmizeFileName))
{
foreach (var s in File.ReadAllLines(custmizeFileName))
{
- CustomizeTips.Add(s);
+ if (!string.IsNullOrEmpty(s) && !CustomizeTips.ContainsKey(s))
+ {
+ CustomizeTips[s] = new TipNotifyOptions(true, true, false);
+ }
}
+ // 遷移後刪除舊檔
+ try { File.Delete(custmizeFileName); } catch { }
}
}
@@ -78,10 +90,9 @@ private void GenConfigFile()
{
var iniData = new IniData();
var baseSection = iniData[settingsBaseSection];
+ baseSection[nameof(AppName)] = "CgLogListener";
baseSection[nameof(CgLogPath)] = string.Empty;
- baseSection[nameof(PlaySound)] = "1";
baseSection[nameof(SoundVol)] = "5";
- baseSection[nameof(CustomNotify)] = "0";
var fileIniDataParser = new FileIniDataParser();
fileIniDataParser.WriteFile(settingsFileName, iniData);
@@ -93,21 +104,24 @@ private void UpdateConfig()
var iniData = new IniData();
var baseSection = iniData[settingsBaseSection];
+ baseSection[nameof(AppName)] = AppName;
baseSection[nameof(CgLogPath)] = CgLogPath;
- baseSection[nameof(PlaySound)] = PlaySound ? "1" : "0";
baseSection[nameof(SoundVol)] = SoundVol.ToString();
- baseSection[nameof(CustomNotify)] = CustomNotify ? "1" : "0";
baseSection[nameof(CustomNotifier)] = CustomNotifier;
var standardTipData = iniData[settingsStandardTipsSection];
foreach (var kv in StandardTips)
{
- standardTipData[kv.Key] = kv.Value ? "1" : "0";
+ standardTipData[kv.Key] = kv.Value.ToString();
}
- fileIniDataParser.WriteFile(settingsFileName, iniData);
+ var customTipData = iniData[settingsCustomTipsSection];
+ foreach (var kv in CustomizeTips)
+ {
+ customTipData[kv.Key] = kv.Value.ToString();
+ }
- File.WriteAllLines(custmizeFileName, CustomizeTips);
+ fileIniDataParser.WriteFile(settingsFileName, iniData);
}
internal void SetCgLogPath(string cgLogPath)
@@ -116,15 +130,39 @@ internal void SetCgLogPath(string cgLogPath)
UpdateConfig();
}
- internal void SetStandardTip(string nameInSetting, bool @checked)
+ internal void SetStandardTip(string nameInSetting, TipNotifyOptions options)
+ {
+ StandardTips[nameInSetting] = options;
+ UpdateConfig();
+ }
+
+ internal void SetStandardTipEnabled(string nameInSetting, bool enabled)
+ {
+ if (!StandardTips.ContainsKey(nameInSetting))
+ {
+ StandardTips[nameInSetting] = new TipNotifyOptions();
+ }
+ StandardTips[nameInSetting].Enabled = enabled;
+ UpdateConfig();
+ }
+
+ internal void SetStandardTipPlaySound(string nameInSetting, bool playSound)
{
- StandardTips[nameInSetting] = @checked;
+ if (!StandardTips.ContainsKey(nameInSetting))
+ {
+ StandardTips[nameInSetting] = new TipNotifyOptions();
+ }
+ StandardTips[nameInSetting].PlaySound = playSound;
UpdateConfig();
}
- internal void SetPlaySound(bool @checked)
+ internal void SetStandardTipSendMail(string nameInSetting, bool sendMail)
{
- PlaySound = @checked;
+ if (!StandardTips.ContainsKey(nameInSetting))
+ {
+ StandardTips[nameInSetting] = new TipNotifyOptions();
+ }
+ StandardTips[nameInSetting].SendMail = sendMail;
UpdateConfig();
}
@@ -134,27 +172,73 @@ internal void SetSoundVol(int value)
UpdateConfig();
}
- internal void AddCustmizeTip(string value)
+ internal void AddCustomizeTip(string keyword, TipNotifyOptions options)
{
- CustomizeTips.Add(value);
+ CustomizeTips[keyword] = options;
UpdateConfig();
}
- internal void RemoveCustmizeTip(string value)
+ internal void RemoveCustomizeTip(string keyword)
{
- CustomizeTips.Remove(value);
+ CustomizeTips.Remove(keyword);
UpdateConfig();
}
+ internal void SetCustomizeTipEnabled(string keyword, bool enabled)
+ {
+ if (CustomizeTips.ContainsKey(keyword))
+ {
+ CustomizeTips[keyword].Enabled = enabled;
+ UpdateConfig();
+ }
+ }
+
+ internal void SetCustomizeTipPlaySound(string keyword, bool playSound)
+ {
+ if (CustomizeTips.ContainsKey(keyword))
+ {
+ CustomizeTips[keyword].PlaySound = playSound;
+ UpdateConfig();
+ }
+ }
+
+ internal void SetCustomizeTipSendMail(string keyword, bool sendMail)
+ {
+ if (CustomizeTips.ContainsKey(keyword))
+ {
+ CustomizeTips[keyword].SendMail = sendMail;
+ UpdateConfig();
+ }
+ }
+
internal void SetCustomNotifier(string value)
{
CustomNotifier = value;
UpdateConfig();
}
- internal void SetCustomNotify(bool value)
+ internal void SetStandardTipCustomNotify(string nameInSetting, bool customNotify)
+ {
+ if (!StandardTips.ContainsKey(nameInSetting))
+ {
+ StandardTips[nameInSetting] = new TipNotifyOptions();
+ }
+ StandardTips[nameInSetting].CustomNotify = customNotify;
+ UpdateConfig();
+ }
+
+ internal void SetCustomizeTipCustomNotify(string keyword, bool customNotify)
+ {
+ if (CustomizeTips.ContainsKey(keyword))
+ {
+ CustomizeTips[keyword].CustomNotify = customNotify;
+ UpdateConfig();
+ }
+ }
+
+ internal void SetAppName(string value)
{
- CustomNotify = value;
+ AppName = string.IsNullOrEmpty(value) ? "CgLogListener" : value;
UpdateConfig();
}
}
diff --git a/src/CgLogListener/TipNotifyOptions.cs b/src/CgLogListener/TipNotifyOptions.cs
new file mode 100644
index 0000000..4863b65
--- /dev/null
+++ b/src/CgLogListener/TipNotifyOptions.cs
@@ -0,0 +1,92 @@
+namespace CgLogListener
+{
+ public class TipNotifyOptions
+ {
+ public string Text { get; set; }
+ public string RegexPattern { get; set; }
+ public bool Enabled { get; set; }
+ public bool PlaySound { get; set; }
+ public bool SendMail { get; set; }
+ public bool IsRegex { get; set; }
+ public bool CustomNotify { get; set; }
+
+ public TipNotifyOptions()
+ {
+ Enabled = false;
+ PlaySound = true;
+ SendMail = false;
+ IsRegex = false;
+ CustomNotify = false;
+ }
+
+ public TipNotifyOptions(bool enabled, bool playSound, bool sendMail, bool isRegex = false, bool customNotify = false)
+ {
+ Enabled = enabled;
+ PlaySound = playSound;
+ SendMail = sendMail;
+ IsRegex = isRegex;
+ CustomNotify = customNotify;
+ }
+
+ ///
+ /// 從 INI 字串解析
+ /// 新格式: "Text|RegexPattern|enabled,playSound,sendMail,isRegex,customNotify" 如 "通知文字|regex.*pattern|1,1,0,0,1"
+ /// 舊格式: "enabled,playSound,sendMail,isRegex,customNotify" 如 "1,1,0,0,1" (相容)
+ ///
+ public static TipNotifyOptions Parse(string value)
+ {
+ if (string.IsNullOrEmpty(value))
+ {
+ return new TipNotifyOptions();
+ }
+
+ // 檢查是否為新格式 (包含 |)
+ if (value.Contains("|"))
+ {
+ var sections = value.Split('|');
+ if (sections.Length >= 3)
+ {
+ var flags = sections[2].Split(',');
+ return new TipNotifyOptions
+ {
+ Text = sections[0],
+ RegexPattern = sections[1],
+ Enabled = flags.Length > 0 && flags[0] == "1",
+ PlaySound = flags.Length > 1 && flags[1] == "1",
+ SendMail = flags.Length > 2 && flags[2] == "1",
+ IsRegex = flags.Length > 3 && flags[3] == "1",
+ CustomNotify = flags.Length > 4 && flags[4] == "1"
+ };
+ }
+ }
+
+ // 舊格式相容
+ var parts = value.Split(',');
+ return new TipNotifyOptions
+ {
+ Enabled = parts.Length > 0 && parts[0] == "1",
+ PlaySound = parts.Length > 1 && parts[1] == "1",
+ SendMail = parts.Length > 2 && parts[2] == "1",
+ IsRegex = parts.Length > 3 && parts[3] == "1",
+ CustomNotify = parts.Length > 4 && parts[4] == "1"
+ };
+ }
+
+ ///
+ /// 轉成 INI 字串
+ /// 如果有 Text 或 RegexPattern,使用新格式: "Text|RegexPattern|enabled,playSound,sendMail,isRegex,customNotify"
+ /// 否則使用舊格式: "enabled,playSound,sendMail,isRegex,customNotify"
+ ///
+ public override string ToString()
+ {
+ var flags = $"{(Enabled ? "1" : "0")},{(PlaySound ? "1" : "0")},{(SendMail ? "1" : "0")},{(IsRegex ? "1" : "0")},{(CustomNotify ? "1" : "0")}";
+
+ if (!string.IsNullOrEmpty(Text) || !string.IsNullOrEmpty(RegexPattern))
+ {
+ return $"{Text ?? ""}|{RegexPattern ?? ""}|{flags}";
+ }
+
+ return flags;
+ }
+ }
+}
diff --git a/src/DiscordNotifier/DiscordNotifier.csproj b/src/DiscordNotifier/DiscordNotifier.csproj
index 000c25d..91af799 100644
--- a/src/DiscordNotifier/DiscordNotifier.csproj
+++ b/src/DiscordNotifier/DiscordNotifier.csproj
@@ -1,61 +1,87 @@
-
-
- Debug
- AnyCPU
- {7F0CAD47-7583-479B-8BD2-7901CD5B81CB}
- Exe
- DiscordNotifier
- DiscordNotifier
- v4.6
- 512
- true
- true
-
-
- AnyCPU
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
-
-
- AnyCPU
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
-
-
-
- ..\packages\ini-parser.2.5.2\lib\net20\INIFileParser.dll
-
-
- ..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ Debug
+ AnyCPU
+ {7F0CAD47-7583-479B-8BD2-7901CD5B81CB}
+ Exe
+ DiscordNotifier
+ DiscordNotifier
+ v4.6
+ 512
+ true
+ true
+ publish\
+ true
+ Disk
+ false
+ Foreground
+ 7
+ Days
+ false
+ false
+ true
+ 0
+ 1.0.0.%2a
+ false
+ false
+ true
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ AnyCPU
+ pdbonly
+ true
+ ..\CgLogListener\bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+ ..\packages\ini-parser.2.5.2\lib\net20\INIFileParser.dll
+
+
+ ..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+
+
+ False
+ .NET Framework 3.5 SP1
+ false
+
+
+
\ No newline at end of file
diff --git a/src/TelegramNotifier/TelegramNotifier.csproj b/src/TelegramNotifier/TelegramNotifier.csproj
index 6b52c63..ca34a28 100644
--- a/src/TelegramNotifier/TelegramNotifier.csproj
+++ b/src/TelegramNotifier/TelegramNotifier.csproj
@@ -27,7 +27,7 @@
AnyCPU
pdbonly
true
- bin\Release\
+ ..\CgLogListener\bin\Release\
TRACE
prompt
4
@@ -52,8 +52,12 @@
-
+
+
+ PreserveNewest
+
+
\ No newline at end of file