├── .gitignore ├── README.md └── src ├── CgLogListener.sln ├── CgLogListener ├── CgLogHandler.cs ├── CgLogListener.csproj ├── CgLogListenerControls.cs ├── FormCustomNotifierPrompt.Designer.cs ├── FormCustomNotifierPrompt.cs ├── FormCustomNotifierPrompt.resx ├── FormMain.Designer.cs ├── FormMain.cs ├── FormMain.resx ├── FormPrompt.Designer.cs ├── FormPrompt.cs ├── FormPrompt.resx ├── INotifyMessage.cs ├── Program.cs ├── Properties │ └── AssemblyInfo.cs ├── Resource.Designer.cs ├── Resource.resx ├── Settings.cs ├── app.config ├── icon.ico ├── packages.config └── sound.wav ├── DiscordNotifier ├── App.config ├── DiscordNotifier.csproj ├── DiscordNotifier.ini ├── DiscordNotifyHelper.cs ├── Program.cs └── packages.config ├── LineNotifier ├── App.config ├── LineNotifier.csproj ├── LineNotifier.ini ├── LineNotifyHelper.cs ├── Program.cs ├── Properties │ └── AssemblyInfo.cs └── packages.config └── TelegramNotifier ├── App.config ├── Program.cs ├── Properties └── AssemblyInfo.cs ├── Telegram.ini ├── TelegramNotifier.csproj ├── TelegramNotifyHelper.cs └── packages.config /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | CgLogListener 2 | ==== 3 | 設計給魔力寶貝使用的輔助程式 4 | 5 | 主要為監視Log資料夾, 並依據內建(或自訂)的關鍵字提醒警示 6 | 7 | ![demo](https://i.imgur.com/28FDH9D.png) 8 | 9 | ![demo](https://i.imgur.com/xT5ZAwe.png) 10 | 11 | 12 | 目錄下可替換wav 13 | -------------------------------------------------------------------------------- /src/CgLogListener.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.11.35327.3 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CgLogListener", "CgLogListener\CgLogListener.csproj", "{23398F23-F4C0-4741-A11D-69F2736770EB}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TelegramNotifier", "TelegramNotifier\TelegramNotifier.csproj", "{C4491C6F-82CE-4D33-B1CC-8C4F16984E97}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DiscordNotifier", "DiscordNotifier\DiscordNotifier.csproj", "{7F0CAD47-7583-479B-8BD2-7901CD5B81CB}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {23398F23-F4C0-4741-A11D-69F2736770EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {23398F23-F4C0-4741-A11D-69F2736770EB}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {23398F23-F4C0-4741-A11D-69F2736770EB}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {23398F23-F4C0-4741-A11D-69F2736770EB}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {C4491C6F-82CE-4D33-B1CC-8C4F16984E97}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {C4491C6F-82CE-4D33-B1CC-8C4F16984E97}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {C4491C6F-82CE-4D33-B1CC-8C4F16984E97}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {C4491C6F-82CE-4D33-B1CC-8C4F16984E97}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {7F0CAD47-7583-479B-8BD2-7901CD5B81CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {7F0CAD47-7583-479B-8BD2-7901CD5B81CB}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {7F0CAD47-7583-479B-8BD2-7901CD5B81CB}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {7F0CAD47-7583-479B-8BD2-7901CD5B81CB}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(ExtensibilityGlobals) = postSolution 35 | SolutionGuid = {4BE494EE-D0BD-4436-A173-50AC60420E68} 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /src/CgLogListener/CgLogHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | 8 | namespace CgLogListener 9 | { 10 | public class CgLogHandler : IDisposable 11 | { 12 | readonly object locker = new object(); 13 | readonly string logPath; 14 | private readonly FileSystemWatcher fsw; 15 | private string latestLog; 16 | public delegate void onNewLog(string message); 17 | public event onNewLog OnNewLog; 18 | 19 | public CgLogHandler(string path) 20 | { 21 | if (string.IsNullOrEmpty(path) || 22 | !Directory.Exists(path) || 23 | !ValidationPath(path)) 24 | { 25 | throw new ArgumentException(nameof(path)); 26 | } 27 | 28 | logPath = Path.Combine(path, "Log"); 29 | fsw = new FileSystemWatcher(logPath) 30 | { 31 | Filter = "*.txt", 32 | NotifyFilter = NotifyFilters.Size | NotifyFilters.LastWrite, 33 | EnableRaisingEvents = true 34 | }; 35 | fsw.Changed += Fsw_Changed; 36 | } 37 | 38 | public static bool ValidationPath(string path) 39 | { 40 | try 41 | { 42 | if (!Directory.Exists(path)) 43 | { 44 | return false; 45 | } 46 | 47 | if (Directory.Exists(Path.Combine(path, "Log"))) 48 | { 49 | return true; 50 | } 51 | 52 | return false; 53 | } 54 | catch { return false; } 55 | } 56 | 57 | private void Fsw_Changed(object sender, FileSystemEventArgs e) 58 | { 59 | try 60 | { 61 | lock (locker) 62 | { 63 | using (var stream = new FileStream(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 64 | { 65 | var l = stream.Length - 2; 66 | stream.Seek(l, SeekOrigin.Begin); 67 | var stack = new Stack(); 68 | while (true) 69 | { 70 | stream.Seek(--l, SeekOrigin.Begin); 71 | var tmp = stream.ReadByte(); 72 | if (tmp == '\n') 73 | { 74 | break; 75 | } 76 | else 77 | { 78 | stack.Push((byte)tmp); 79 | } 80 | } 81 | 82 | var native = stack.ToArray(); 83 | var b = Encoding.Convert(Encoding.GetEncoding("BIG5"), Encoding.UTF8, native); 84 | var log = Encoding.UTF8.GetString(b).Replace("", " "); 85 | /* 86 | * 多視窗時可能會連續偵測到相同的句子 (並且時間會一樣) 87 | * 所以會有一個變數去紀錄最後的 log, 並拿來比對當次的 log 88 | * 若 not equals 才會觸發事件 89 | */ 90 | if (!log.Equals(latestLog)) 91 | { 92 | latestLog = log; 93 | OnNewLog?.Invoke(log); 94 | } 95 | } 96 | } 97 | } 98 | catch { } 99 | } 100 | 101 | public void Dispose() 102 | { 103 | fsw.Dispose(); 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/CgLogListener/CgLogListener.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {23398F23-F4C0-4741-A11D-69F2736770EB} 8 | WinExe 9 | CgLogListener 10 | CgLogListener 11 | v4.6 12 | 512 13 | false 14 | 15 | publish\ 16 | true 17 | Disk 18 | false 19 | Foreground 20 | 7 21 | Days 22 | false 23 | false 24 | true 25 | 0 26 | 2.1.0.%2a 27 | false 28 | true 29 | 30 | 31 | AnyCPU 32 | true 33 | full 34 | false 35 | bin\Debug\ 36 | DEBUG;TRACE 37 | prompt 38 | 4 39 | false 40 | 41 | 42 | AnyCPU 43 | pdbonly 44 | true 45 | bin\Release\ 46 | TRACE 47 | prompt 48 | 4 49 | false 50 | 51 | 52 | icon.ico 53 | 54 | 55 | 56 | ..\packages\ini-parser.2.5.2\lib\net20\INIFileParser.dll 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | Form 77 | 78 | 79 | FormMain.cs 80 | 81 | 82 | Form 83 | 84 | 85 | FormCustomNotifierPrompt.cs 86 | 87 | 88 | Form 89 | 90 | 91 | FormPrompt.cs 92 | 93 | 94 | True 95 | True 96 | Resource.resx 97 | 98 | 99 | 100 | 101 | 102 | 103 | Component 104 | 105 | 106 | FormMain.cs 107 | 108 | 109 | FormCustomNotifierPrompt.cs 110 | 111 | 112 | FormPrompt.cs 113 | 114 | 115 | ResXFileCodeGenerator 116 | Resource.Designer.cs 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | Always 125 | 126 | 127 | 128 | 129 | False 130 | .NET Framework 3.5 SP1 131 | false 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /src/CgLogListener/CgLogListenerControls.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Text.RegularExpressions; 6 | using System.Windows.Forms; 7 | 8 | namespace CgLogListener 9 | { 10 | public class CgLogListenerCheckBox : CheckBox, INotifyMessage 11 | { 12 | public string NameInSetting { get; set; } 13 | public string RegexPattern { get; set; } 14 | 15 | public bool Notify(string message) 16 | { 17 | var settings = Settings.GetInstance(); 18 | 19 | if (settings.StandardTips.TryGetValue(NameInSetting, out bool value) && 20 | value && 21 | Regex.IsMatch(message, RegexPattern)) 22 | { 23 | return true; 24 | } 25 | 26 | return false; 27 | } 28 | } 29 | 30 | public class CgLogListenerTrackBar : TrackBar 31 | { 32 | public string NameInSetting { get; set; } 33 | } 34 | 35 | public class CgLogListenerListBox : ListBox, INotifyMessage 36 | { 37 | public NotifyIcon NotifyIcon { get; set; } 38 | 39 | public bool Notify(string message) 40 | { 41 | var settings = Settings.GetInstance(); 42 | foreach (var s in settings.CustomizeTips) 43 | { 44 | var split = s.Split('|'); 45 | 46 | if (message.Contains(split[0])) 47 | { 48 | if (split.Length > 1) 49 | { 50 | var exps = split[1].Split(','); 51 | 52 | return !exps.Any(x => message.Contains(x));// !message.Contains(split[1]); 53 | } 54 | else 55 | { 56 | return true; 57 | } 58 | } 59 | } 60 | 61 | return false; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/CgLogListener/FormCustomNotifierPrompt.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace CgLogListener 2 | { 3 | partial class FormCustomNotifierPrompt 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.btnOk = new System.Windows.Forms.Button(); 32 | this.label1 = new System.Windows.Forms.Label(); 33 | this.txtValue = new System.Windows.Forms.TextBox(); 34 | this.SuspendLayout(); 35 | // 36 | // btnOk 37 | // 38 | this.btnOk.Location = new System.Drawing.Point(299, 2); 39 | this.btnOk.Name = "btnOk"; 40 | this.btnOk.Size = new System.Drawing.Size(57, 26); 41 | this.btnOk.TabIndex = 3; 42 | this.btnOk.Text = "設定"; 43 | this.btnOk.UseVisualStyleBackColor = true; 44 | this.btnOk.Click += new System.EventHandler(this.btnOk_Click); 45 | // 46 | // label1 47 | // 48 | this.label1.AutoSize = true; 49 | this.label1.Location = new System.Drawing.Point(11, 10); 50 | this.label1.Name = "label1"; 51 | this.label1.Size = new System.Drawing.Size(47, 15); 52 | this.label1.TabIndex = 1; 53 | this.label1.Text = "Notifier"; 54 | // 55 | // txtValue 56 | // 57 | this.txtValue.Location = new System.Drawing.Point(83, 7); 58 | this.txtValue.Name = "txtValue"; 59 | this.txtValue.Size = new System.Drawing.Size(210, 21); 60 | this.txtValue.TabIndex = 1; 61 | // 62 | // FormCustomNotifierPrompt 63 | // 64 | this.AcceptButton = this.btnOk; 65 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 15F); 66 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 67 | this.ClientSize = new System.Drawing.Size(368, 35); 68 | this.ControlBox = false; 69 | this.Controls.Add(this.txtValue); 70 | this.Controls.Add(this.label1); 71 | this.Controls.Add(this.btnOk); 72 | this.Font = new System.Drawing.Font("微軟正黑體", 7.8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(136))); 73 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 74 | this.MaximizeBox = false; 75 | this.MinimizeBox = false; 76 | this.Name = "FormCustomNotifierPrompt"; 77 | this.ShowIcon = false; 78 | this.ShowInTaskbar = false; 79 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; 80 | this.Text = " "; 81 | this.ResumeLayout(false); 82 | this.PerformLayout(); 83 | 84 | } 85 | 86 | #endregion 87 | 88 | private System.Windows.Forms.Button btnOk; 89 | private System.Windows.Forms.Label label1; 90 | private System.Windows.Forms.TextBox txtValue; 91 | } 92 | } -------------------------------------------------------------------------------- /src/CgLogListener/FormCustomNotifierPrompt.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Windows.Forms; 9 | 10 | namespace CgLogListener 11 | { 12 | public partial class FormCustomNotifierPrompt : Form 13 | { 14 | FormCustomNotifierPrompt() 15 | { 16 | InitializeComponent(); 17 | this.ImeMode = ImeMode.OnHalf; 18 | } 19 | 20 | public static DialogResult ShowDialog(IWin32Window owner, out string value) 21 | { 22 | FormCustomNotifierPrompt f = new FormCustomNotifierPrompt(); 23 | DialogResult result = f.ShowDialog(owner); 24 | value = f.txtValue.Text; 25 | 26 | return result; 27 | } 28 | 29 | private void btnOk_Click(object sender, EventArgs e) 30 | { 31 | this.DialogResult = DialogResult.OK; 32 | this.Close(); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/CgLogListener/FormCustomNotifierPrompt.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /src/CgLogListener/FormMain.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace CgLogListener 2 | { 3 | partial class FormMain 4 | { 5 | /// 6 | /// 設計工具所需的變數。 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// 清除任何使用中的資源。 12 | /// 13 | /// 如果應該處置 Managed 資源則為 true,否則為 false。 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form 設計工具產生的程式碼 24 | 25 | /// 26 | /// 此為設計工具支援所需的方法 - 請勿使用程式碼編輯器修改 27 | /// 這個方法的內容。 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.components = new System.ComponentModel.Container(); 32 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormMain)); 33 | this.notifyIcon = new System.Windows.Forms.NotifyIcon(this.components); 34 | this.notifyIconContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components); 35 | this.toolOpen = new System.Windows.Forms.ToolStripMenuItem(); 36 | this.toolMinsize = new System.Windows.Forms.ToolStripMenuItem(); 37 | this.toolSep1 = new System.Windows.Forms.ToolStripSeparator(); 38 | this.toolExit = new System.Windows.Forms.ToolStripMenuItem(); 39 | this.txtCgLogPath = new System.Windows.Forms.TextBox(); 40 | this.btnSelectLogPath = new System.Windows.Forms.Button(); 41 | this.panel1 = new System.Windows.Forms.Panel(); 42 | this.checkBox1 = new System.Windows.Forms.CheckBox(); 43 | this.cgLogListenerTrackBar = new CgLogListener.CgLogListenerTrackBar(); 44 | this.cgLogListenerSettingCheckBox1 = new CgLogListener.CgLogListenerCheckBox(); 45 | this.cgLogListenerCheckBox6 = new CgLogListener.CgLogListenerCheckBox(); 46 | this.cgLogListenerCheckBox5 = new CgLogListener.CgLogListenerCheckBox(); 47 | this.cgLogListenerCheckBox4 = new CgLogListener.CgLogListenerCheckBox(); 48 | this.cgLogListenerCheckBox3 = new CgLogListener.CgLogListenerCheckBox(); 49 | this.label1 = new System.Windows.Forms.Label(); 50 | this.cgLogListenerListBox = new CgLogListener.CgLogListenerListBox(); 51 | this.btnDelCus = new System.Windows.Forms.Button(); 52 | this.btnAddCus = new System.Windows.Forms.Button(); 53 | this.cgLogListenerCheckBox2 = new CgLogListener.CgLogListenerCheckBox(); 54 | this.cgLogListenerCheckBox1 = new CgLogListener.CgLogListenerCheckBox(); 55 | this.btnExit = new System.Windows.Forms.Button(); 56 | this.linkLabel1 = new System.Windows.Forms.LinkLabel(); 57 | this.notifyIconContextMenu.SuspendLayout(); 58 | this.panel1.SuspendLayout(); 59 | ((System.ComponentModel.ISupportInitialize)(this.cgLogListenerTrackBar)).BeginInit(); 60 | this.SuspendLayout(); 61 | // 62 | // notifyIcon 63 | // 64 | this.notifyIcon.BalloonTipTitle = "魔力Log監視"; 65 | this.notifyIcon.ContextMenuStrip = this.notifyIconContextMenu; 66 | this.notifyIcon.Icon = ((System.Drawing.Icon)(resources.GetObject("notifyIcon.Icon"))); 67 | this.notifyIcon.Text = "魔力Log監視"; 68 | this.notifyIcon.Visible = true; 69 | this.notifyIcon.DoubleClick += new System.EventHandler(this.NotifyIcon_DoubleClick); 70 | // 71 | // notifyIconContextMenu 72 | // 73 | this.notifyIconContextMenu.ImageScalingSize = new System.Drawing.Size(20, 20); 74 | this.notifyIconContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { 75 | this.toolOpen, 76 | this.toolMinsize, 77 | this.toolSep1, 78 | this.toolExit}); 79 | this.notifyIconContextMenu.Name = "notifyIconContextMenu"; 80 | this.notifyIconContextMenu.ShowImageMargin = false; 81 | this.notifyIconContextMenu.Size = new System.Drawing.Size(86, 76); 82 | // 83 | // toolOpen 84 | // 85 | this.toolOpen.Name = "toolOpen"; 86 | this.toolOpen.Size = new System.Drawing.Size(85, 22); 87 | this.toolOpen.Text = "開啟"; 88 | this.toolOpen.Click += new System.EventHandler(this.ToolOpen_Click); 89 | // 90 | // toolMinsize 91 | // 92 | this.toolMinsize.Name = "toolMinsize"; 93 | this.toolMinsize.Size = new System.Drawing.Size(85, 22); 94 | this.toolMinsize.Text = "最小化"; 95 | this.toolMinsize.Click += new System.EventHandler(this.ToolMinsize_Click); 96 | // 97 | // toolSep1 98 | // 99 | this.toolSep1.Name = "toolSep1"; 100 | this.toolSep1.Size = new System.Drawing.Size(82, 6); 101 | // 102 | // toolExit 103 | // 104 | this.toolExit.Name = "toolExit"; 105 | this.toolExit.Size = new System.Drawing.Size(85, 22); 106 | this.toolExit.Text = "結束"; 107 | this.toolExit.Click += new System.EventHandler(this.ToolExit_Click); 108 | // 109 | // txtCgLogPath 110 | // 111 | this.txtCgLogPath.Location = new System.Drawing.Point(11, 9); 112 | this.txtCgLogPath.Margin = new System.Windows.Forms.Padding(2); 113 | this.txtCgLogPath.Name = "txtCgLogPath"; 114 | this.txtCgLogPath.ReadOnly = true; 115 | this.txtCgLogPath.Size = new System.Drawing.Size(219, 22); 116 | this.txtCgLogPath.TabIndex = 1; 117 | // 118 | // btnSelectLogPath 119 | // 120 | this.btnSelectLogPath.Location = new System.Drawing.Point(234, 8); 121 | this.btnSelectLogPath.Margin = new System.Windows.Forms.Padding(2); 122 | this.btnSelectLogPath.Name = "btnSelectLogPath"; 123 | this.btnSelectLogPath.Size = new System.Drawing.Size(53, 22); 124 | this.btnSelectLogPath.TabIndex = 2; 125 | this.btnSelectLogPath.Text = "選擇"; 126 | this.btnSelectLogPath.UseVisualStyleBackColor = true; 127 | this.btnSelectLogPath.Click += new System.EventHandler(this.BtnSelectLogPath_Click); 128 | // 129 | // panel1 130 | // 131 | this.panel1.Controls.Add(this.checkBox1); 132 | this.panel1.Controls.Add(this.cgLogListenerTrackBar); 133 | this.panel1.Controls.Add(this.cgLogListenerSettingCheckBox1); 134 | this.panel1.Controls.Add(this.cgLogListenerCheckBox6); 135 | this.panel1.Controls.Add(this.cgLogListenerCheckBox5); 136 | this.panel1.Controls.Add(this.cgLogListenerCheckBox4); 137 | this.panel1.Controls.Add(this.cgLogListenerCheckBox3); 138 | this.panel1.Controls.Add(this.label1); 139 | this.panel1.Controls.Add(this.cgLogListenerListBox); 140 | this.panel1.Controls.Add(this.btnDelCus); 141 | this.panel1.Controls.Add(this.btnAddCus); 142 | this.panel1.Controls.Add(this.cgLogListenerCheckBox2); 143 | this.panel1.Controls.Add(this.cgLogListenerCheckBox1); 144 | this.panel1.Location = new System.Drawing.Point(11, 38); 145 | this.panel1.Margin = new System.Windows.Forms.Padding(2); 146 | this.panel1.Name = "panel1"; 147 | this.panel1.Size = new System.Drawing.Size(276, 255); 148 | this.panel1.TabIndex = 6; 149 | // 150 | // checkBox1 151 | // 152 | this.checkBox1.AutoSize = true; 153 | this.checkBox1.Location = new System.Drawing.Point(2, 230); 154 | this.checkBox1.Name = "checkBox1"; 155 | this.checkBox1.Size = new System.Drawing.Size(93, 16); 156 | this.checkBox1.TabIndex = 13; 157 | this.checkBox1.Text = "Custom Notify"; 158 | this.checkBox1.UseVisualStyleBackColor = true; 159 | // 160 | // cgLogListenerTrackBar 161 | // 162 | this.cgLogListenerTrackBar.AutoSize = false; 163 | this.cgLogListenerTrackBar.LargeChange = 1; 164 | this.cgLogListenerTrackBar.Location = new System.Drawing.Point(2, 197); 165 | this.cgLogListenerTrackBar.Name = "cgLogListenerTrackBar"; 166 | this.cgLogListenerTrackBar.NameInSetting = "SoundVol"; 167 | this.cgLogListenerTrackBar.Size = new System.Drawing.Size(108, 27); 168 | this.cgLogListenerTrackBar.TabIndex = 12; 169 | this.cgLogListenerTrackBar.Value = 5; 170 | // 171 | // cgLogListenerSettingCheckBox1 172 | // 173 | this.cgLogListenerSettingCheckBox1.AutoSize = true; 174 | this.cgLogListenerSettingCheckBox1.Location = new System.Drawing.Point(2, 172); 175 | this.cgLogListenerSettingCheckBox1.Name = "cgLogListenerSettingCheckBox1"; 176 | this.cgLogListenerSettingCheckBox1.NameInSetting = "PlaySound"; 177 | this.cgLogListenerSettingCheckBox1.RegexPattern = null; 178 | this.cgLogListenerSettingCheckBox1.Size = new System.Drawing.Size(72, 16); 179 | this.cgLogListenerSettingCheckBox1.TabIndex = 8; 180 | this.cgLogListenerSettingCheckBox1.Text = "播放音效"; 181 | this.cgLogListenerSettingCheckBox1.UseVisualStyleBackColor = true; 182 | // 183 | // cgLogListenerCheckBox6 184 | // 185 | this.cgLogListenerCheckBox6.AutoSize = true; 186 | this.cgLogListenerCheckBox6.Location = new System.Drawing.Point(2, 124); 187 | this.cgLogListenerCheckBox6.Name = "cgLogListenerCheckBox6"; 188 | this.cgLogListenerCheckBox6.NameInSetting = "ReMaze"; 189 | this.cgLogListenerCheckBox6.RegexPattern = "你感覺到一股不可思議的力量,而『.*』好像快(要?)消失了。"; 190 | this.cgLogListenerCheckBox6.Size = new System.Drawing.Size(96, 16); 191 | this.cgLogListenerCheckBox6.TabIndex = 8; 192 | this.cgLogListenerCheckBox6.Text = "迷宮重組通知"; 193 | this.cgLogListenerCheckBox6.UseVisualStyleBackColor = true; 194 | // 195 | // cgLogListenerCheckBox5 196 | // 197 | this.cgLogListenerCheckBox5.AutoSize = true; 198 | this.cgLogListenerCheckBox5.Location = new System.Drawing.Point(2, 99); 199 | this.cgLogListenerCheckBox5.Name = "cgLogListenerCheckBox5"; 200 | this.cgLogListenerCheckBox5.NameInSetting = "Sell"; 201 | this.cgLogListenerCheckBox5.RegexPattern = "您順利賣掉了一個.*,(收入|獲得).*魔幣!"; 202 | this.cgLogListenerCheckBox5.Size = new System.Drawing.Size(96, 16); 203 | this.cgLogListenerCheckBox5.TabIndex = 8; 204 | this.cgLogListenerCheckBox5.Text = "擺攤售出通知"; 205 | this.cgLogListenerCheckBox5.UseVisualStyleBackColor = true; 206 | // 207 | // cgLogListenerCheckBox4 208 | // 209 | this.cgLogListenerCheckBox4.AutoSize = true; 210 | this.cgLogListenerCheckBox4.Location = new System.Drawing.Point(2, 74); 211 | this.cgLogListenerCheckBox4.Name = "cgLogListenerCheckBox4"; 212 | this.cgLogListenerCheckBox4.NameInSetting = "PlayerJoin"; 213 | this.cgLogListenerCheckBox4.RegexPattern = "加入了(你|您)的隊伍。"; 214 | this.cgLogListenerCheckBox4.Size = new System.Drawing.Size(108, 16); 215 | this.cgLogListenerCheckBox4.TabIndex = 8; 216 | this.cgLogListenerCheckBox4.Text = "被加入隊伍通知"; 217 | this.cgLogListenerCheckBox4.UseVisualStyleBackColor = true; 218 | // 219 | // cgLogListenerCheckBox3 220 | // 221 | this.cgLogListenerCheckBox3.AutoSize = true; 222 | this.cgLogListenerCheckBox3.Location = new System.Drawing.Point(2, 49); 223 | this.cgLogListenerCheckBox3.Name = "cgLogListenerCheckBox3"; 224 | this.cgLogListenerCheckBox3.NameInSetting = "MP0"; 225 | this.cgLogListenerCheckBox3.RegexPattern = "魔力不足。"; 226 | this.cgLogListenerCheckBox3.Size = new System.Drawing.Size(96, 16); 227 | this.cgLogListenerCheckBox3.TabIndex = 8; 228 | this.cgLogListenerCheckBox3.Text = "魔力不足通知"; 229 | this.cgLogListenerCheckBox3.UseVisualStyleBackColor = true; 230 | // 231 | // label1 232 | // 233 | this.label1.AutoSize = true; 234 | this.label1.Location = new System.Drawing.Point(126, 2); 235 | this.label1.Name = "label1"; 236 | this.label1.Size = new System.Drawing.Size(65, 12); 237 | this.label1.TabIndex = 11; 238 | this.label1.Text = "自訂關鍵字"; 239 | // 240 | // cgLogListenerListBox 241 | // 242 | this.cgLogListenerListBox.FormattingEnabled = true; 243 | this.cgLogListenerListBox.ItemHeight = 12; 244 | this.cgLogListenerListBox.Location = new System.Drawing.Point(127, 20); 245 | this.cgLogListenerListBox.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3); 246 | this.cgLogListenerListBox.Name = "cgLogListenerListBox"; 247 | this.cgLogListenerListBox.NotifyIcon = this.notifyIcon; 248 | this.cgLogListenerListBox.Size = new System.Drawing.Size(147, 148); 249 | this.cgLogListenerListBox.TabIndex = 9; 250 | // 251 | // btnDelCus 252 | // 253 | this.btnDelCus.Location = new System.Drawing.Point(178, 181); 254 | this.btnDelCus.Margin = new System.Windows.Forms.Padding(2); 255 | this.btnDelCus.Name = "btnDelCus"; 256 | this.btnDelCus.Size = new System.Drawing.Size(47, 22); 257 | this.btnDelCus.TabIndex = 10; 258 | this.btnDelCus.Text = "移除"; 259 | this.btnDelCus.UseVisualStyleBackColor = true; 260 | this.btnDelCus.Click += new System.EventHandler(this.BtnDelCus_Click); 261 | // 262 | // btnAddCus 263 | // 264 | this.btnAddCus.Location = new System.Drawing.Point(127, 181); 265 | this.btnAddCus.Margin = new System.Windows.Forms.Padding(2); 266 | this.btnAddCus.Name = "btnAddCus"; 267 | this.btnAddCus.Size = new System.Drawing.Size(47, 22); 268 | this.btnAddCus.TabIndex = 9; 269 | this.btnAddCus.Text = "增加"; 270 | this.btnAddCus.UseVisualStyleBackColor = true; 271 | this.btnAddCus.Click += new System.EventHandler(this.BtnAddCus_Click); 272 | // 273 | // cgLogListenerCheckBox2 274 | // 275 | this.cgLogListenerCheckBox2.AutoSize = true; 276 | this.cgLogListenerCheckBox2.Location = new System.Drawing.Point(2, 25); 277 | this.cgLogListenerCheckBox2.Margin = new System.Windows.Forms.Padding(2); 278 | this.cgLogListenerCheckBox2.Name = "cgLogListenerCheckBox2"; 279 | this.cgLogListenerCheckBox2.NameInSetting = "ItemFull"; 280 | this.cgLogListenerCheckBox2.RegexPattern = "物品欄沒有空位。"; 281 | this.cgLogListenerCheckBox2.Size = new System.Drawing.Size(84, 16); 282 | this.cgLogListenerCheckBox2.TabIndex = 1; 283 | this.cgLogListenerCheckBox2.Text = "道具滿通知"; 284 | this.cgLogListenerCheckBox2.UseVisualStyleBackColor = true; 285 | // 286 | // cgLogListenerCheckBox1 287 | // 288 | this.cgLogListenerCheckBox1.AutoSize = true; 289 | this.cgLogListenerCheckBox1.Location = new System.Drawing.Point(2, 2); 290 | this.cgLogListenerCheckBox1.Margin = new System.Windows.Forms.Padding(2); 291 | this.cgLogListenerCheckBox1.Name = "cgLogListenerCheckBox1"; 292 | this.cgLogListenerCheckBox1.NameInSetting = "Health"; 293 | this.cgLogListenerCheckBox1.RegexPattern = "在工作時不小心受傷了。"; 294 | this.cgLogListenerCheckBox1.Size = new System.Drawing.Size(96, 16); 295 | this.cgLogListenerCheckBox1.TabIndex = 1; 296 | this.cgLogListenerCheckBox1.Text = "採集受傷通知"; 297 | this.cgLogListenerCheckBox1.UseVisualStyleBackColor = true; 298 | // 299 | // btnExit 300 | // 301 | this.btnExit.Anchor = System.Windows.Forms.AnchorStyles.Bottom; 302 | this.btnExit.Location = new System.Drawing.Point(198, 300); 303 | this.btnExit.Margin = new System.Windows.Forms.Padding(2); 304 | this.btnExit.Name = "btnExit"; 305 | this.btnExit.Size = new System.Drawing.Size(89, 22); 306 | this.btnExit.TabIndex = 7; 307 | this.btnExit.Text = "結束程式"; 308 | this.btnExit.UseVisualStyleBackColor = true; 309 | this.btnExit.Click += new System.EventHandler(this.BtnExit_Click); 310 | // 311 | // linkLabel1 312 | // 313 | this.linkLabel1.AutoSize = true; 314 | this.linkLabel1.Location = new System.Drawing.Point(9, 311); 315 | this.linkLabel1.Name = "linkLabel1"; 316 | this.linkLabel1.Size = new System.Drawing.Size(65, 12); 317 | this.linkLabel1.TabIndex = 7; 318 | this.linkLabel1.TabStop = true; 319 | this.linkLabel1.Text = "關於本程式"; 320 | this.linkLabel1.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.LinkLabel1_LinkClicked); 321 | // 322 | // FormMain 323 | // 324 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); 325 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 326 | this.ClientSize = new System.Drawing.Size(298, 333); 327 | this.Controls.Add(this.linkLabel1); 328 | this.Controls.Add(this.panel1); 329 | this.Controls.Add(this.btnSelectLogPath); 330 | this.Controls.Add(this.txtCgLogPath); 331 | this.Controls.Add(this.btnExit); 332 | this.Font = new System.Drawing.Font("新細明體", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 333 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 334 | this.Margin = new System.Windows.Forms.Padding(2, 3, 2, 3); 335 | this.MaximizeBox = false; 336 | this.Name = "FormMain"; 337 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; 338 | this.Text = "魔力Log監視"; 339 | this.MinimumSizeChanged += new System.EventHandler(this.FormMain_MinimumSizeChanged); 340 | this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FormMain_FormClosing); 341 | this.Load += new System.EventHandler(this.FrmMain_Load); 342 | this.Resize += new System.EventHandler(this.FormMain_Resize); 343 | this.notifyIconContextMenu.ResumeLayout(false); 344 | this.panel1.ResumeLayout(false); 345 | this.panel1.PerformLayout(); 346 | ((System.ComponentModel.ISupportInitialize)(this.cgLogListenerTrackBar)).EndInit(); 347 | this.ResumeLayout(false); 348 | this.PerformLayout(); 349 | 350 | } 351 | 352 | #endregion 353 | 354 | private System.Windows.Forms.NotifyIcon notifyIcon; 355 | private System.Windows.Forms.TextBox txtCgLogPath; 356 | private System.Windows.Forms.Button btnSelectLogPath; 357 | private System.Windows.Forms.Panel panel1; 358 | private System.Windows.Forms.Button btnDelCus; 359 | private System.Windows.Forms.Button btnAddCus; 360 | private System.Windows.Forms.Button btnExit; 361 | private System.Windows.Forms.ContextMenuStrip notifyIconContextMenu; 362 | private System.Windows.Forms.ToolStripMenuItem toolOpen; 363 | private System.Windows.Forms.ToolStripMenuItem toolMinsize; 364 | private System.Windows.Forms.ToolStripSeparator toolSep1; 365 | private System.Windows.Forms.ToolStripMenuItem toolExit; 366 | private CgLogListenerListBox cgLogListenerListBox; 367 | private System.Windows.Forms.Label label1; 368 | private CgLogListenerCheckBox cgLogListenerCheckBox1; 369 | private CgLogListenerCheckBox cgLogListenerCheckBox2; 370 | private CgLogListenerCheckBox cgLogListenerCheckBox3; 371 | private CgLogListenerCheckBox cgLogListenerCheckBox4; 372 | private CgLogListenerCheckBox cgLogListenerCheckBox5; 373 | private System.Windows.Forms.LinkLabel linkLabel1; 374 | private CgLogListenerCheckBox cgLogListenerSettingCheckBox1; 375 | private CgLogListenerCheckBox cgLogListenerCheckBox6; 376 | private CgLogListenerTrackBar cgLogListenerTrackBar; 377 | private System.Windows.Forms.CheckBox checkBox1; 378 | } 379 | } 380 | 381 | -------------------------------------------------------------------------------- /src/CgLogListener/FormMain.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Web; 6 | using System.Windows.Forms; 7 | using System.Windows.Media; 8 | 9 | namespace CgLogListener 10 | { 11 | public partial class FormMain : Form 12 | { 13 | private Settings settings; 14 | private CgLogHandler watcher; 15 | private readonly MediaPlayer mp = new MediaPlayer(); 16 | 17 | public FormMain() 18 | { 19 | InitializeComponent(); 20 | 21 | // fix IME bug 22 | ImeMode = ImeMode.OnHalf; 23 | Icon = Resource.icon; 24 | notifyIcon.Icon = Resource.icon; 25 | } 26 | 27 | private void FrmMain_Load(object sender, EventArgs e) 28 | { 29 | settings = Settings.GetInstance(); 30 | 31 | if (string.IsNullOrEmpty(settings.CgLogPath)) 32 | { 33 | string cgLogPath = settings.CgLogPath; 34 | 35 | if (!SelectLogPath(out cgLogPath)) 36 | { 37 | this.Close(); 38 | return; 39 | } 40 | 41 | settings.SetCgLogPath(cgLogPath); 42 | } 43 | 44 | if (!Directory.Exists(settings.CgLogPath) || !CgLogHandler.ValidationPath(settings.CgLogPath)) 45 | { 46 | // the dir path invalid, set to default and exit 47 | settings.SetCgLogPath(string.Empty); 48 | MessageBox.Show(this, "設定檔路徑錯誤, 請重新啟動", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); 49 | this.Close(); 50 | return; 51 | } 52 | 53 | BindWatcher(); 54 | 55 | // set playsound check 56 | cgLogListenerSettingCheckBox1.Checked = settings.PlaySound; 57 | 58 | // set playsound vol 59 | cgLogListenerTrackBar.Value = settings.SoundVol; 60 | 61 | // set line notify 62 | checkBox1.Checked = settings.CustomNotify; 63 | 64 | // set default tips check 65 | foreach (var chk in panel1.Controls.OfType()) 66 | { 67 | // skip playsound 68 | if (chk == cgLogListenerSettingCheckBox1) { continue; } 69 | 70 | settings.StandardTips.TryGetValue(chk.NameInSetting, out bool isEnable); 71 | chk.Checked = isEnable; 72 | } 73 | 74 | // set custom tips items 75 | settings.CustomizeTips 76 | .ForEach(s => 77 | { 78 | if (!string.IsNullOrEmpty(s)) 79 | { 80 | cgLogListenerListBox.Items.Add(s); 81 | } 82 | }); 83 | 84 | cgLogListenerCheckBox1.CheckedChanged += CgLogListenerCheckBox_CheckedChanged; 85 | cgLogListenerCheckBox2.CheckedChanged += CgLogListenerCheckBox_CheckedChanged; 86 | cgLogListenerCheckBox3.CheckedChanged += CgLogListenerCheckBox_CheckedChanged; 87 | cgLogListenerCheckBox4.CheckedChanged += CgLogListenerCheckBox_CheckedChanged; 88 | cgLogListenerCheckBox5.CheckedChanged += CgLogListenerCheckBox_CheckedChanged; 89 | cgLogListenerCheckBox6.CheckedChanged += CgLogListenerCheckBox_CheckedChanged; 90 | cgLogListenerSettingCheckBox1.CheckedChanged += CgLogListenerSettingCheckBox1_CheckedChanged; 91 | cgLogListenerTrackBar.ValueChanged += CgLogListenerTrackBar_ValueChanged; 92 | checkBox1.CheckedChanged += CheckBox1_CheckedChanged; 93 | } 94 | 95 | private void CgLogListenerCheckBox_CheckedChanged(object sender, EventArgs e) 96 | { 97 | var chk = (CgLogListenerCheckBox)sender; 98 | settings.SetStandardTip(chk.NameInSetting, chk.Checked); 99 | } 100 | 101 | private void CgLogListenerSettingCheckBox1_CheckedChanged(object sender, EventArgs e) 102 | { 103 | var chk = (CgLogListenerCheckBox)sender; 104 | settings.SetPlaySound(chk.Checked); 105 | } 106 | 107 | private void CgLogListenerTrackBar_ValueChanged(object sender, EventArgs e) 108 | { 109 | var bar = (CgLogListenerTrackBar)sender; 110 | settings.SetSoundVol(bar.Value); 111 | } 112 | 113 | private void BtnSelectLogPath_Click(object sender, EventArgs e) 114 | { 115 | if (SelectLogPath(out _)) 116 | { 117 | watcher.Dispose(); 118 | BindWatcher(); 119 | } 120 | } 121 | 122 | bool SelectLogPath(out string path) 123 | { 124 | path = null; 125 | var dialog = new FolderBrowserDialog() 126 | { 127 | ShowNewFolderButton = false, 128 | Description = @"請選擇魔力寶貝的目錄 (e.g. D:\CrossGate\)" 129 | }; 130 | 131 | while (true) 132 | { 133 | var result = dialog.ShowDialog(this); 134 | 135 | if (result == DialogResult.Cancel) 136 | { 137 | return false; 138 | } 139 | 140 | if (result == DialogResult.OK) 141 | { 142 | if (!CgLogHandler.ValidationPath(dialog.SelectedPath)) 143 | { 144 | MessageBox.Show(this, "請選擇魔力寶貝的目錄", "錯誤的路徑", MessageBoxButtons.OK, MessageBoxIcon.Warning); 145 | continue; 146 | } 147 | 148 | path = dialog.SelectedPath; 149 | return true; 150 | } 151 | } 152 | } 153 | 154 | void BindWatcher() 155 | { 156 | txtCgLogPath.Text = settings.CgLogPath; 157 | watcher = new CgLogHandler(settings.CgLogPath); 158 | watcher.OnNewLog += Watcher_OnNewLog; 159 | } 160 | 161 | void Watcher_OnNewLog(string log) 162 | { 163 | foreach (var n in panel1.Controls.OfType()) 164 | { 165 | if (n.Notify(log)) 166 | { 167 | notifyIcon.ShowBalloonTip(1, notifyIcon.BalloonTipTitle, log, ToolTipIcon.None); 168 | 169 | const string soundName = "sound.wav"; 170 | if (settings.PlaySound && File.Exists(soundName)) 171 | { 172 | Invoke((Action)delegate 173 | { 174 | mp.Stop(); 175 | mp.Open(new Uri(new FileInfo(soundName).FullName)); 176 | mp.Volume = settings.SoundVol / 10d; 177 | mp.Play(); 178 | }); 179 | } 180 | 181 | if (settings.CustomNotify) 182 | { 183 | foreach (var notifier in settings.CustomNotifier.Split(',')) 184 | { 185 | try 186 | { 187 | ProcessStartInfo p = new ProcessStartInfo(notifier, $"\"{log}\"") 188 | { 189 | WindowStyle = ProcessWindowStyle.Hidden, 190 | CreateNoWindow = true 191 | }; 192 | Process.Start(p); 193 | } 194 | catch { } 195 | } 196 | } 197 | 198 | // break if was trigger 199 | break; 200 | } 201 | } 202 | } 203 | 204 | private void BtnAddCus_Click(object sender, EventArgs e) 205 | { 206 | if (FormPrompt.ShowDialog(this, out string value) != DialogResult.OK || 207 | string.IsNullOrEmpty(value)) 208 | { 209 | return; 210 | } 211 | 212 | settings.AddCustmizeTip(value); 213 | cgLogListenerListBox.Items.Add(value); 214 | } 215 | 216 | private void BtnDelCus_Click(object sender, EventArgs e) 217 | { 218 | if (cgLogListenerListBox.SelectedIndex < 0) 219 | { 220 | return; 221 | } 222 | 223 | var selectItem = (string)cgLogListenerListBox.SelectedItem; 224 | settings.RemoveCustmizeTip(selectItem); 225 | cgLogListenerListBox.Items.Remove(selectItem); 226 | } 227 | 228 | private void CheckBox1_CheckedChanged(object sender, EventArgs e) 229 | { 230 | if (checkBox1.Checked) 231 | { 232 | FormCustomNotifierPrompt.ShowDialog(this, out string value); 233 | settings.SetCustomNotify(true); 234 | settings.SetCustomNotifier(value); 235 | } 236 | else 237 | { 238 | settings.SetCustomNotify(false); 239 | settings.SetCustomNotifier(string.Empty); 240 | } 241 | } 242 | 243 | #region notifyIcon, window minsize and exit ... 244 | 245 | private void NotifyIcon_DoubleClick(object sender, EventArgs e) 246 | { 247 | if (this.WindowState == FormWindowState.Minimized) 248 | { 249 | this.Visible = true; 250 | this.WindowState = FormWindowState.Normal; 251 | } 252 | else if (this.WindowState == FormWindowState.Normal) 253 | { 254 | this.WindowState = FormWindowState.Minimized; 255 | } 256 | } 257 | 258 | private void BtnExit_Click(object sender, EventArgs e) 259 | { 260 | this.Close(); 261 | } 262 | 263 | private void ToolOpen_Click(object sender, EventArgs e) 264 | { 265 | this.Visible = true; 266 | this.WindowState = FormWindowState.Normal; 267 | } 268 | 269 | private void ToolMinsize_Click(object sender, EventArgs e) 270 | { 271 | this.WindowState = FormWindowState.Minimized; 272 | } 273 | 274 | private void ToolExit_Click(object sender, EventArgs e) 275 | { 276 | this.Close(); 277 | } 278 | 279 | private void FormMain_MinimumSizeChanged(object sender, EventArgs e) 280 | { 281 | this.WindowState = FormWindowState.Minimized; 282 | } 283 | 284 | private void FormMain_Resize(object sender, EventArgs e) 285 | { 286 | if (this.WindowState == FormWindowState.Minimized) 287 | { 288 | this.Visible = false; 289 | } 290 | } 291 | 292 | private void FormMain_FormClosing(object sender, FormClosingEventArgs e) 293 | { 294 | watcher?.Dispose(); 295 | notifyIcon?.Dispose(); 296 | } 297 | 298 | #endregion 299 | 300 | private void LinkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) 301 | { 302 | System.Diagnostics.Process.Start("https://github.com/WindOfNet/CgLogListener"); 303 | } 304 | } 305 | } 306 | -------------------------------------------------------------------------------- /src/CgLogListener/FormMain.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 17, 17 122 | 123 | 124 | 147, 17 125 | 126 | 127 | 128 | 129 | AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAABILAAASCwAAAAAAAAAA 130 | AAD///8A////AP///wBVVVUAVVVVAFVVVQArKysWAQEBuQEBAdMAAAAdAAAAAAAAAAAAAAAA////AP// 131 | /wD///8A////AP///wD///8AVVVVAFVVVQBVVVUALS0tZsjJyf+ln5//AwMDmAAAAAAAAAAAAAAAAP// 132 | /wD///8A////AP///wD///8A////AFVVVQBVVVUAVVVVAC0tLWbc3d3/uq6u/wMDA5gAAAAAAAAAAAAA 133 | AAD///8A////AP///wD///8A////AP///wArWmsAK1prACtaawAtLS1mtLS0/4+Pj/8DAwOYADBAAAAw 134 | QAAAMEAA////AP///wD///8A////AP///wD///8AAF+AAABfgAAAX4ALCmeGh6vw8Omq8PDpCmeGhwBf 135 | gAsAX4AAAF+AAP///wD///8A////AP///wD///8A////AABfgAAAX4AAAF+AMDyOpY6o7+/opu7u6DyO 136 | pY4AX4AwAF+AAABfgAD///8A////AP///wD///8A////AP///wAAYYMAAGGDAwBggW5/w864nOvr45rr 137 | 6+J/w864AF+AbgBfgAMAX4AA////AP///wD///8A////AP///wD///8AAGuQAABliEkyi6SRqu/w5obl 138 | 5d6O5+ffsvLy5jWIoZQAX4BLAF+AAP///wD///8A////AP///wD///8A////AABskSMTeJiAnefp2V7Y 139 | 2N5c2Njcbd3d3Yjl5d+w7e/aFXCOhwBggSb///8A////AP///wD///8A////AP///wAAcJZdbsPQsXDe 140 | 3uFJ0tLYRNDQ2UrT09tk2trckOjo4oDF0LYAYoRm////AP///wD///8A////AP///wD///8AAHSbcqru 141 | 79iE5OTVhuXl02/e3tNL0tLXS9LS227d3d2w7/DYAGeKfv///wD///8A////AP///wD///8A////AAB3 142 | n26+9fXcsfLy2bPy8tik7u7Wb97e00TQ0Nle2NjcrfDw3ABskHz///8A////AP///wD///8A////AP// 143 | /wAAeqNam9vlub729uC28/PZs/Ly2Ibl5dNJ0tLYZNra34zV3r0AcJZl////AP///wD///8A////AP// 144 | /wD///8AAH2mKyyXt3bJ+PnevPX13q/y8th+4uLTWNbW3Jzq694nkK59AHOaMP///wD///8A////AP// 145 | /wD///8A////AAB+qAEAfqg/Kpe4c5PX47Oy8fLOmOnqzXfO2bQjkrJ4AHigQwB2ngH///8A////AP// 146 | /wD///8A////AP///wAAfqgAAH6oAAB/qSgAf6lRAH6oYgB+p2IAfaZUAHylKQB5oQAAdp4A////AP// 147 | /wD///8A/D8AAPw/AAD8PwAA/D8AAPgfAAD4HwAA8A8AAPAPAADgBwAA4AcAAOAHAADgBwAA4AcAAOAH 148 | AADgBwAA+B8AAA== 149 | 150 | 151 | -------------------------------------------------------------------------------- /src/CgLogListener/FormPrompt.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace CgLogListener 2 | { 3 | partial class FormPrompt 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.btnOk = new System.Windows.Forms.Button(); 32 | this.label1 = new System.Windows.Forms.Label(); 33 | this.txtValue = new System.Windows.Forms.TextBox(); 34 | this.btnCancel = new System.Windows.Forms.Button(); 35 | this.label2 = new System.Windows.Forms.Label(); 36 | this.txtExp = new System.Windows.Forms.TextBox(); 37 | this.SuspendLayout(); 38 | // 39 | // btnOk 40 | // 41 | this.btnOk.Location = new System.Drawing.Point(299, 2); 42 | this.btnOk.Name = "btnOk"; 43 | this.btnOk.Size = new System.Drawing.Size(57, 26); 44 | this.btnOk.TabIndex = 3; 45 | this.btnOk.Text = "設定"; 46 | this.btnOk.UseVisualStyleBackColor = true; 47 | this.btnOk.Click += new System.EventHandler(this.btnOk_Click); 48 | // 49 | // label1 50 | // 51 | this.label1.AutoSize = true; 52 | this.label1.Location = new System.Drawing.Point(11, 10); 53 | this.label1.Name = "label1"; 54 | this.label1.Size = new System.Drawing.Size(40, 15); 55 | this.label1.TabIndex = 1; 56 | this.label1.Text = "關鍵字"; 57 | // 58 | // txtValue 59 | // 60 | this.txtValue.Location = new System.Drawing.Point(67, 7); 61 | this.txtValue.Name = "txtValue"; 62 | this.txtValue.Size = new System.Drawing.Size(210, 21); 63 | this.txtValue.TabIndex = 1; 64 | // 65 | // btnCancel 66 | // 67 | this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; 68 | this.btnCancel.Location = new System.Drawing.Point(299, 31); 69 | this.btnCancel.Name = "btnCancel"; 70 | this.btnCancel.Size = new System.Drawing.Size(57, 26); 71 | this.btnCancel.TabIndex = 4; 72 | this.btnCancel.Text = "取消"; 73 | this.btnCancel.UseVisualStyleBackColor = true; 74 | this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click); 75 | // 76 | // label2 77 | // 78 | this.label2.AutoSize = true; 79 | this.label2.Location = new System.Drawing.Point(11, 37); 80 | this.label2.Name = "label2"; 81 | this.label2.Size = new System.Drawing.Size(95, 15); 82 | this.label2.TabIndex = 1; 83 | this.label2.Text = "排除 (以逗號分隔)"; 84 | // 85 | // txtExp 86 | // 87 | this.txtExp.Location = new System.Drawing.Point(112, 34); 88 | this.txtExp.Name = "txtExp"; 89 | this.txtExp.Size = new System.Drawing.Size(165, 21); 90 | this.txtExp.TabIndex = 2; 91 | // 92 | // FormPrompt 93 | // 94 | this.AcceptButton = this.btnOk; 95 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 15F); 96 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 97 | this.CancelButton = this.btnCancel; 98 | this.ClientSize = new System.Drawing.Size(368, 64); 99 | this.ControlBox = false; 100 | this.Controls.Add(this.txtExp); 101 | this.Controls.Add(this.label2); 102 | this.Controls.Add(this.txtValue); 103 | this.Controls.Add(this.label1); 104 | this.Controls.Add(this.btnCancel); 105 | this.Controls.Add(this.btnOk); 106 | this.Font = new System.Drawing.Font("微軟正黑體", 7.8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(136))); 107 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 108 | this.MaximizeBox = false; 109 | this.MinimizeBox = false; 110 | this.Name = "FormPrompt"; 111 | this.ShowIcon = false; 112 | this.ShowInTaskbar = false; 113 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; 114 | this.Text = " "; 115 | this.ResumeLayout(false); 116 | this.PerformLayout(); 117 | 118 | } 119 | 120 | #endregion 121 | 122 | private System.Windows.Forms.Button btnOk; 123 | private System.Windows.Forms.Label label1; 124 | private System.Windows.Forms.TextBox txtValue; 125 | private System.Windows.Forms.Button btnCancel; 126 | private System.Windows.Forms.Label label2; 127 | private System.Windows.Forms.TextBox txtExp; 128 | } 129 | } -------------------------------------------------------------------------------- /src/CgLogListener/FormPrompt.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Windows.Forms; 9 | 10 | namespace CgLogListener 11 | { 12 | public partial class FormPrompt : Form 13 | { 14 | FormPrompt() 15 | { 16 | InitializeComponent(); 17 | this.ImeMode = ImeMode.OnHalf; 18 | } 19 | 20 | public static DialogResult ShowDialog(IWin32Window owner, out string value) 21 | { 22 | FormPrompt f = new FormPrompt(); 23 | DialogResult result = f.ShowDialog(owner); 24 | value = f.txtValue.Text; 25 | if (!string.IsNullOrWhiteSpace(f.txtExp.Text)) 26 | { 27 | value += $"|{f.txtExp.Text}"; 28 | } 29 | 30 | return result; 31 | } 32 | 33 | private void btnOk_Click(object sender, EventArgs e) 34 | { 35 | this.DialogResult = DialogResult.OK; 36 | this.Close(); 37 | } 38 | 39 | private void btnCancel_Click(object sender, EventArgs e) 40 | { 41 | this.DialogResult = DialogResult.No; 42 | this.Close(); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/CgLogListener/FormPrompt.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /src/CgLogListener/INotifyMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace CgLogListener 7 | { 8 | public interface INotifyMessage 9 | { 10 | bool Notify(string message); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/CgLogListener/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Runtime.InteropServices; 6 | using System.Threading; 7 | using System.Windows.Forms; 8 | 9 | namespace CgLogListener 10 | { 11 | static class Program 12 | { 13 | static Mutex _mutex; 14 | /// 15 | /// 應用程式的主要進入點。 16 | /// 17 | [STAThread] 18 | static void Main() 19 | { 20 | bool createNew; 21 | 22 | Attribute guid_attr = Attribute.GetCustomAttribute(Assembly.GetExecutingAssembly(), typeof(GuidAttribute)); 23 | string guid = ((GuidAttribute)guid_attr).Value; 24 | _mutex = new Mutex(true, guid, out createNew); 25 | 26 | if (false == createNew) 27 | { 28 | MessageBox.Show("已經有正在執行的CgLogListener", "", MessageBoxButtons.OK, MessageBoxIcon.Stop); 29 | return; 30 | } 31 | 32 | _mutex.ReleaseMutex(); 33 | 34 | Application.EnableVisualStyles(); 35 | Application.SetCompatibleTextRenderingDefault(false); 36 | Application.Run(new FormMain()); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/CgLogListener/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 組件的一般資訊是由下列的屬性集控制。 6 | // 變更這些屬性的值即可修改組件的相關 7 | // 資訊。 8 | [assembly: AssemblyTitle("LogWatcher")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("LogWatcher")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 將 ComVisible 設為 false 可對 COM 元件隱藏 18 | // 組件中的類型。若必須從 COM 存取此組件中的類型, 19 | // 的類型,請在該類型上將 ComVisible 屬性設定為 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 下列 GUID 為專案公開 (Expose) 至 COM 時所要使用的 typelib ID 23 | [assembly: Guid("23398f23-f4c0-4741-a11d-69f2736770eb")] 24 | 25 | // 組件的版本資訊由下列四個值所組成: 26 | // 27 | // 主要版本 28 | // 次要版本 29 | // 組建編號 30 | // 修訂編號 31 | // 32 | // 您可以指定所有的值,或將組建編號或修訂編號設為預設值 33 | // 指定為預設值: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /src/CgLogListener/Resource.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 這段程式碼是由工具產生的。 4 | // 執行階段版本:4.0.30319.42000 5 | // 6 | // 對這個檔案所做的變更可能會造成錯誤的行為,而且如果重新產生程式碼, 7 | // 變更將會遺失。 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace CgLogListener { 12 | using System; 13 | 14 | 15 | /// 16 | /// 用於查詢當地語系化字串等的強類型資源類別。 17 | /// 18 | // 這個類別是自動產生的,是利用 StronglyTypedResourceBuilder 19 | // 類別透過 ResGen 或 Visual Studio 這類工具。 20 | // 若要加入或移除成員,請編輯您的 .ResX 檔,然後重新執行 ResGen 21 | // (利用 /str 選項),或重建您的 VS 專案。 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resource { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resource() { 33 | } 34 | 35 | /// 36 | /// 傳回這個類別使用的快取的 ResourceManager 執行個體。 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CgLogListener.Resource", typeof(Resource).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// 覆寫目前執行緒的 CurrentUICulture 屬性,對象是所有 51 | /// 使用這個強類型資源類別的資源查閱。 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// 查詢類似 (圖示) 的類型 System.Drawing.Icon 當地語系化資源。 65 | /// 66 | internal static System.Drawing.Icon icon { 67 | get { 68 | object obj = ResourceManager.GetObject("icon", resourceCulture); 69 | return ((System.Drawing.Icon)(obj)); 70 | } 71 | } 72 | 73 | /// 74 | /// 查詢類似 System.IO.MemoryStream 的類型 System.IO.UnmanagedMemoryStream 當地語系化資源。 75 | /// 76 | internal static System.IO.UnmanagedMemoryStream sound { 77 | get { 78 | return ResourceManager.GetStream("sound", resourceCulture); 79 | } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/CgLogListener/Resource.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 122 | icon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 123 | 124 | 125 | sound.wav;System.IO.MemoryStream, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 126 | 127 | -------------------------------------------------------------------------------- /src/CgLogListener/Settings.cs: -------------------------------------------------------------------------------- 1 | using IniParser; 2 | using IniParser.Model; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Text; 8 | 9 | namespace CgLogListener 10 | { 11 | public sealed class Settings 12 | { 13 | static Settings instance; 14 | const string settingsFileName = "settings.ini"; 15 | const string settingsBaseSection = "base"; 16 | const string settingsStandardTipsSection = "standard tips"; 17 | const string custmizeFileName = "custmize.dat"; 18 | 19 | public bool CustomNotify { get; private set; } 20 | public string CustomNotifier { get; private set; } 21 | public bool PlaySound { get; private set; } 22 | public int SoundVol { get; private set; } 23 | public string CgLogPath { get; private set; } 24 | public Dictionary StandardTips { get; private set; } = new Dictionary(); 25 | public List CustomizeTips { get; private set; } = new List(); 26 | 27 | public static Settings GetInstance() 28 | { 29 | if (instance == null) 30 | { 31 | instance = new Settings(); 32 | instance.Load(); 33 | } 34 | 35 | return instance; 36 | } 37 | 38 | public void Load() 39 | { 40 | if (!File.Exists(Path.Combine(Directory.GetCurrentDirectory(), settingsFileName))) 41 | { 42 | // gen new conf file 43 | GenConfigFile(); 44 | } 45 | 46 | // load settings 47 | LoadSettings(); 48 | } 49 | 50 | private void LoadSettings() 51 | { 52 | var fileIniDataParser = new FileIniDataParser(); 53 | var iniData = fileIniDataParser.ReadFile(settingsFileName); 54 | 55 | var baseData = iniData[settingsBaseSection]; 56 | CgLogPath = baseData[nameof(CgLogPath)]; 57 | PlaySound = baseData[nameof(PlaySound)] == "1"; 58 | SoundVol = int.Parse(baseData[nameof(SoundVol)]); 59 | CustomNotify = baseData[nameof(CustomNotify)] == "1"; 60 | CustomNotifier = baseData[nameof(CustomNotifier)]; 61 | 62 | var standardTipData = iniData[settingsStandardTipsSection]; 63 | foreach (var kd in standardTipData) 64 | { 65 | StandardTips.Add(kd.KeyName, kd.Value == "1"); 66 | } 67 | 68 | if (File.Exists(custmizeFileName)) 69 | { 70 | foreach (var s in File.ReadAllLines(custmizeFileName)) 71 | { 72 | CustomizeTips.Add(s); 73 | } 74 | } 75 | } 76 | 77 | private void GenConfigFile() 78 | { 79 | var iniData = new IniData(); 80 | var baseSection = iniData[settingsBaseSection]; 81 | baseSection[nameof(CgLogPath)] = string.Empty; 82 | baseSection[nameof(PlaySound)] = "1"; 83 | baseSection[nameof(SoundVol)] = "5"; 84 | baseSection[nameof(CustomNotify)] = "0"; 85 | 86 | var fileIniDataParser = new FileIniDataParser(); 87 | fileIniDataParser.WriteFile(settingsFileName, iniData); 88 | } 89 | 90 | private void UpdateConfig() 91 | { 92 | var fileIniDataParser = new FileIniDataParser(); 93 | var iniData = new IniData(); 94 | 95 | var baseSection = iniData[settingsBaseSection]; 96 | baseSection[nameof(CgLogPath)] = CgLogPath; 97 | baseSection[nameof(PlaySound)] = PlaySound ? "1" : "0"; 98 | baseSection[nameof(SoundVol)] = SoundVol.ToString(); 99 | baseSection[nameof(CustomNotify)] = CustomNotify ? "1" : "0"; 100 | baseSection[nameof(CustomNotifier)] = CustomNotifier; 101 | 102 | var standardTipData = iniData[settingsStandardTipsSection]; 103 | foreach (var kv in StandardTips) 104 | { 105 | standardTipData[kv.Key] = kv.Value ? "1" : "0"; 106 | } 107 | 108 | fileIniDataParser.WriteFile(settingsFileName, iniData); 109 | 110 | File.WriteAllLines(custmizeFileName, CustomizeTips); 111 | } 112 | 113 | internal void SetCgLogPath(string cgLogPath) 114 | { 115 | CgLogPath = cgLogPath; 116 | UpdateConfig(); 117 | } 118 | 119 | internal void SetStandardTip(string nameInSetting, bool @checked) 120 | { 121 | StandardTips[nameInSetting] = @checked; 122 | UpdateConfig(); 123 | } 124 | 125 | internal void SetPlaySound(bool @checked) 126 | { 127 | PlaySound = @checked; 128 | UpdateConfig(); 129 | } 130 | 131 | internal void SetSoundVol(int value) 132 | { 133 | SoundVol = value; 134 | UpdateConfig(); 135 | } 136 | 137 | internal void AddCustmizeTip(string value) 138 | { 139 | CustomizeTips.Add(value); 140 | UpdateConfig(); 141 | } 142 | 143 | internal void RemoveCustmizeTip(string value) 144 | { 145 | CustomizeTips.Remove(value); 146 | UpdateConfig(); 147 | } 148 | 149 | internal void SetCustomNotifier(string value) 150 | { 151 | CustomNotifier = value; 152 | UpdateConfig(); 153 | } 154 | 155 | internal void SetCustomNotify(bool value) 156 | { 157 | CustomNotify = value; 158 | UpdateConfig(); 159 | } 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /src/CgLogListener/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/CgLogListener/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WindOfNet/CgLogListener/c17f15664bf03e0c9d2adba0956efdd21219ec92/src/CgLogListener/icon.ico -------------------------------------------------------------------------------- /src/CgLogListener/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /src/CgLogListener/sound.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WindOfNet/CgLogListener/c17f15664bf03e0c9d2adba0956efdd21219ec92/src/CgLogListener/sound.wav -------------------------------------------------------------------------------- /src/DiscordNotifier/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/DiscordNotifier/DiscordNotifier.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {7F0CAD47-7583-479B-8BD2-7901CD5B81CB} 8 | Exe 9 | DiscordNotifier 10 | DiscordNotifier 11 | v4.6 12 | 512 13 | true 14 | true 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | ..\packages\ini-parser.2.5.2\lib\net20\INIFileParser.dll 38 | 39 | 40 | ..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /src/DiscordNotifier/DiscordNotifier.ini: -------------------------------------------------------------------------------- 1 | webhookUrl= -------------------------------------------------------------------------------- /src/DiscordNotifier/DiscordNotifyHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.Http; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | using Newtonsoft.Json; 6 | 7 | namespace DiscordNotifier 8 | { 9 | public static class DiscordNotifyHelper 10 | { 11 | public static async Task Notify(string webhookUrl, string message) 12 | { 13 | try 14 | { 15 | var payload = new 16 | { 17 | content = message, 18 | username = "CgLogListener", 19 | }; 20 | 21 | var httpClient = new HttpClient(); 22 | 23 | var json = JsonConvert.SerializeObject(payload); 24 | var content = new StringContent(json, Encoding.UTF8, "application/json"); 25 | 26 | var response = await httpClient.PostAsync(webhookUrl, content); 27 | response.EnsureSuccessStatusCode(); 28 | } 29 | catch (Exception ex) 30 | { 31 | Console.WriteLine($"Discord通知送信エラー: {ex.Message}"); 32 | } 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/DiscordNotifier/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using IniParser; 4 | 5 | namespace DiscordNotifier 6 | { 7 | internal class Program 8 | { 9 | static void Main(string[] args) 10 | { 11 | const string iniFilename = "DiscordNotifier.ini"; 12 | 13 | if (!File.Exists(iniFilename)) 14 | { 15 | return; 16 | } 17 | 18 | try 19 | { 20 | var ini = new FileIniDataParser().ReadFile(iniFilename); 21 | if (ini.TryGetKey("webhookUrl", out var webhookUrl) && !string.IsNullOrEmpty(webhookUrl)) 22 | { 23 | DiscordNotifyHelper.Notify(webhookUrl, args[0]).Wait(); 24 | } 25 | } 26 | catch 27 | { 28 | // ignored 29 | } 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/DiscordNotifier/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/LineNotifier/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/LineNotifier/LineNotifier.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {C92CBA62-FECA-4448-A321-186F54B39ED3} 8 | Exe 9 | LineNotifier 10 | LineNotifier 11 | v4.6 12 | 512 13 | true 14 | true 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | ..\packages\ini-parser.2.5.2\lib\net20\INIFileParser.dll 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /src/LineNotifier/LineNotifier.ini: -------------------------------------------------------------------------------- 1 | token= -------------------------------------------------------------------------------- /src/LineNotifier/LineNotifyHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | 5 | namespace LineNotifier 6 | { 7 | public static class LineNotifyHelper 8 | { 9 | public static async Task Notify(string token, string message) 10 | { 11 | using (var lineHttpClient = new HttpClient()) 12 | { 13 | lineHttpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {token}"); 14 | var httpContent = new FormUrlEncodedContent(new Dictionary 15 | { 16 | { "message", message } 17 | }); 18 | 19 | var p = await lineHttpClient.PostAsync("https://notify-api.line.me/api/notify", httpContent); 20 | p.EnsureSuccessStatusCode(); 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/LineNotifier/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using IniParser; 4 | 5 | namespace LineNotifier 6 | { 7 | internal class Program 8 | { 9 | static void Main(string[] args) 10 | { 11 | const string iniFilename = "LineNotifier.ini"; 12 | 13 | if (!File.Exists(iniFilename)) 14 | { 15 | return; 16 | } 17 | 18 | try 19 | { 20 | var ini = new FileIniDataParser().ReadFile(iniFilename); 21 | if (ini.TryGetKey("token", out var token) && !string.IsNullOrEmpty(token)) 22 | { 23 | LineNotifyHelper.Notify(token, args[0]).Wait(); 24 | } 25 | } 26 | catch { } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/LineNotifier/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 組件的一般資訊是由下列的屬性集控制。 6 | // 變更這些屬性的值即可修改組件的相關 7 | // 資訊。 8 | [assembly: AssemblyTitle("LineNotifier")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("LineNotifier")] 13 | [assembly: AssemblyCopyright("Copyright © 2024")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 將 ComVisible 設為 false 可對 COM 元件隱藏 18 | // 組件中的類型。若必須從 COM 存取此組件中的類型, 19 | // 的類型,請在該類型上將 ComVisible 屬性設定為 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 下列 GUID 為專案公開 (Expose) 至 COM 時所要使用的 typelib ID 23 | [assembly: Guid("c92cba62-feca-4448-a321-186f54b39ed3")] 24 | 25 | // 組件的版本資訊由下列四個值所組成: 26 | // 27 | // 主要版本 28 | // 次要版本 29 | // 組建編號 30 | // 修訂 31 | // 32 | [assembly: AssemblyVersion("1.0.0.0")] 33 | [assembly: AssemblyFileVersion("1.0.0.0")] 34 | -------------------------------------------------------------------------------- /src/LineNotifier/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /src/TelegramNotifier/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/TelegramNotifier/Program.cs: -------------------------------------------------------------------------------- 1 | using IniParser; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace TelegramNotifier 10 | { 11 | internal class Program 12 | { 13 | static void Main(string[] args) 14 | { 15 | const string iniFilename = "TelegramNotifier.ini"; 16 | 17 | if (!File.Exists(iniFilename)) 18 | { 19 | return; 20 | } 21 | 22 | try 23 | { 24 | var ini = new FileIniDataParser().ReadFile(iniFilename); 25 | if (ini.TryGetKey("token", out var token) && 26 | !string.IsNullOrEmpty(token) && 27 | ini.TryGetKey("chat_id", out var chatId) && 28 | !string.IsNullOrEmpty(chatId)) 29 | { 30 | TelegramNotifyHelper.Notify(token, chatId, args[0]).Wait(); 31 | } 32 | } 33 | catch { } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/TelegramNotifier/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 組件的一般資訊是由下列的屬性集控制。 6 | // 變更這些屬性的值即可修改組件的相關 7 | // 資訊。 8 | [assembly: AssemblyTitle("TelegramNotifier")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("TelegramNotifier")] 13 | [assembly: AssemblyCopyright("Copyright © 2024")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 將 ComVisible 設為 false 可對 COM 元件隱藏 18 | // 組件中的類型。若必須從 COM 存取此組件中的類型, 19 | // 的類型,請在該類型上將 ComVisible 屬性設定為 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 下列 GUID 為專案公開 (Expose) 至 COM 時所要使用的 typelib ID 23 | [assembly: Guid("c4491c6f-82ce-4d33-b1cc-8c4f16984e97")] 24 | 25 | // 組件的版本資訊由下列四個值所組成: 26 | // 27 | // 主要版本 28 | // 次要版本 29 | // 組建編號 30 | // 修訂 31 | // 32 | [assembly: AssemblyVersion("1.0.0.0")] 33 | [assembly: AssemblyFileVersion("1.0.0.0")] 34 | -------------------------------------------------------------------------------- /src/TelegramNotifier/Telegram.ini: -------------------------------------------------------------------------------- 1 | token=7167863140:AAHZPXV8QPvayVCXb_KnR3ZySa2lcGPi4LE 2 | chat_id=1646740500 -------------------------------------------------------------------------------- /src/TelegramNotifier/TelegramNotifier.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {C4491C6F-82CE-4D33-B1CC-8C4F16984E97} 8 | Exe 9 | TelegramNotifier 10 | TelegramNotifier 11 | v4.6 12 | 512 13 | true 14 | true 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | ..\packages\ini-parser.2.5.2\lib\net20\INIFileParser.dll 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /src/TelegramNotifier/TelegramNotifyHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | 5 | namespace TelegramNotifier 6 | { 7 | public static class TelegramNotifyHelper 8 | { 9 | public static async Task Notify(string token, string chatId, string message) 10 | { 11 | using (var client = new HttpClient()) 12 | { 13 | var httpContent = new FormUrlEncodedContent(new Dictionary 14 | { 15 | { "message", message } 16 | }); 17 | 18 | var p = await client.PostAsync($"https://api.telegram.org/bot{token}/sendMessage?chat_id={chatId}&text={message}", httpContent); 19 | p.EnsureSuccessStatusCode(); 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/TelegramNotifier/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | --------------------------------------------------------------------------------