├── .gitattributes
├── .gitignore
├── README.md
├── ZuAnBot.sln
├── ZuAnBotUpdate
├── Assets
│ └── log4net.config
├── FodyWeavers.xml
├── FodyWeavers.xsd
├── LogHelper.cs
├── ManifestHelper.cs
├── Program.cs
├── Properties
│ └── launchSettings.json
└── ZuAnBotUpdate.csproj
├── ZuAnBot_Wpf
├── Api
│ ├── Apis.cs
│ └── Dtos
│ │ └── VersionDto.cs
├── App.xaml
├── App.xaml.cs
├── Assets
│ ├── Images
│ │ ├── QQ.png
│ │ ├── github.png
│ │ ├── lol.ico
│ │ ├── 删除.png
│ │ ├── 复制.png
│ │ ├── 添加.png
│ │ ├── 祖安.ico
│ │ ├── 祖安助手使用交流群群聊二维码.png
│ │ ├── 粘贴.png
│ │ └── 编辑.png
│ ├── Url.json
│ ├── log4net.config
│ └── wordsLibrary.json
├── Constants
│ ├── DialogTokens.cs
│ ├── Events
│ │ └── Events.cs
│ ├── Params.cs
│ └── Titles.cs
├── FodyWeavers.xml
├── FodyWeavers.xsd
├── Helper
│ ├── EnvConfigs.cs
│ ├── ExceptionExtension.cs
│ ├── GlobalKeyboardHook.cs
│ ├── IPCHelper.cs
│ ├── JsonHelper.cs
│ ├── LocalConfigHelper.cs
│ ├── LogHelper.cs
│ ├── ManifestHelper.cs
│ ├── MessageHelper.cs
│ ├── ProgressFileStream.cs
│ ├── VersionHelper.cs
│ ├── Win32Helper.cs
│ └── WordsHelper.cs
├── Properties
│ ├── AssemblyInfo.cs
│ └── app.manifest
├── ViewModels
│ ├── MainWindowViewModel.cs
│ ├── WordEditViewModel.cs
│ ├── WordLibrary.cs
│ └── WordsLibrarySetViewModel.cs
├── Views
│ ├── Conveters
│ │ └── Bool2Brush.cs
│ ├── MainWindow.xaml
│ ├── MainWindow.xaml.cs
│ ├── WordEdit.xaml
│ ├── WordEdit.xaml.cs
│ ├── WordsLibrarySet.xaml
│ └── WordsLibrarySet.xaml.cs
├── ZuAnBot_Wpf.csproj
└── build.bat
├── 截图_客户端.png
├── 截图_游戏.jpg
├── 截图_自定义词库.png
└── 截图_软件.png
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Build results
17 | [Dd]ebug/
18 | [Dd]ebugPublic/
19 | [Rr]elease/
20 | [Rr]eleases/
21 | x64/
22 | x86/
23 | [Aa][Rr][Mm]/
24 | [Aa][Rr][Mm]64/
25 | bld/
26 | [Bb]in/
27 | [Oo]bj/
28 | [Ll]og/
29 |
30 | # Visual Studio 2015/2017 cache/options directory
31 | .vs/
32 | # Uncomment if you have tasks that create the project's static files in wwwroot
33 | #wwwroot/
34 |
35 | # Visual Studio 2017 auto generated files
36 | Generated\ Files/
37 |
38 | # MSTest test Results
39 | [Tt]est[Rr]esult*/
40 | [Bb]uild[Ll]og.*
41 |
42 | # NUNIT
43 | *.VisualState.xml
44 | TestResult.xml
45 |
46 | # Build Results of an ATL Project
47 | [Dd]ebugPS/
48 | [Rr]eleasePS/
49 | dlldata.c
50 |
51 | # Benchmark Results
52 | BenchmarkDotNet.Artifacts/
53 |
54 | # .NET Core
55 | project.lock.json
56 | project.fragment.lock.json
57 | artifacts/
58 |
59 | # StyleCop
60 | StyleCopReport.xml
61 |
62 | # Files built by Visual Studio
63 | *_i.c
64 | *_p.c
65 | *_h.h
66 | *.ilk
67 | *.meta
68 | *.obj
69 | *.iobj
70 | *.pch
71 | *.pdb
72 | *.ipdb
73 | *.pgc
74 | *.pgd
75 | *.rsp
76 | *.sbr
77 | *.tlb
78 | *.tli
79 | *.tlh
80 | *.tmp
81 | *.tmp_proj
82 | *_wpftmp.csproj
83 | *.log
84 | *.vspscc
85 | *.vssscc
86 | .builds
87 | *.pidb
88 | *.svclog
89 | *.scc
90 |
91 | # Chutzpah Test files
92 | _Chutzpah*
93 |
94 | # Visual C++ cache files
95 | ipch/
96 | *.aps
97 | *.ncb
98 | *.opendb
99 | *.opensdf
100 | *.sdf
101 | *.cachefile
102 | *.VC.db
103 | *.VC.VC.opendb
104 |
105 | # Visual Studio profiler
106 | *.psess
107 | *.vsp
108 | *.vspx
109 | *.sap
110 |
111 | # Visual Studio Trace Files
112 | *.e2e
113 |
114 | # TFS 2012 Local Workspace
115 | $tf/
116 |
117 | # Guidance Automation Toolkit
118 | *.gpState
119 |
120 | # ReSharper is a .NET coding add-in
121 | _ReSharper*/
122 | *.[Rr]e[Ss]harper
123 | *.DotSettings.user
124 |
125 | # JustCode is a .NET coding add-in
126 | .JustCode
127 |
128 | # TeamCity is a build add-in
129 | _TeamCity*
130 |
131 | # DotCover is a Code Coverage Tool
132 | *.dotCover
133 |
134 | # AxoCover is a Code Coverage Tool
135 | .axoCover/*
136 | !.axoCover/settings.json
137 |
138 | # Visual Studio code coverage results
139 | *.coverage
140 | *.coveragexml
141 |
142 | # NCrunch
143 | _NCrunch_*
144 | .*crunch*.local.xml
145 | nCrunchTemp_*
146 |
147 | # MightyMoose
148 | *.mm.*
149 | AutoTest.Net/
150 |
151 | # Web workbench (sass)
152 | .sass-cache/
153 |
154 | # Installshield output folder
155 | [Ee]xpress/
156 |
157 | # DocProject is a documentation generator add-in
158 | DocProject/buildhelp/
159 | DocProject/Help/*.HxT
160 | DocProject/Help/*.HxC
161 | DocProject/Help/*.hhc
162 | DocProject/Help/*.hhk
163 | DocProject/Help/*.hhp
164 | DocProject/Help/Html2
165 | DocProject/Help/html
166 |
167 | # Click-Once directory
168 | publish/
169 |
170 | # Publish Web Output
171 | *.[Pp]ublish.xml
172 | *.azurePubxml
173 | # Note: Comment the next line if you want to checkin your web deploy settings,
174 | # but database connection strings (with potential passwords) will be unencrypted
175 | *.pubxml
176 | *.publishproj
177 |
178 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
179 | # checkin your Azure Web App publish settings, but sensitive information contained
180 | # in these scripts will be unencrypted
181 | PublishScripts/
182 |
183 | # NuGet Packages
184 | *.nupkg
185 | # The packages folder can be ignored because of Package Restore
186 | **/[Pp]ackages/*
187 | # except build/, which is used as an MSBuild target.
188 | !**/[Pp]ackages/build/
189 | # Uncomment if necessary however generally it will be regenerated when needed
190 | #!**/[Pp]ackages/repositories.config
191 | # NuGet v3's project.json files produces more ignorable files
192 | *.nuget.props
193 | *.nuget.targets
194 |
195 | # Microsoft Azure Build Output
196 | csx/
197 | *.build.csdef
198 |
199 | # Microsoft Azure Emulator
200 | ecf/
201 | rcf/
202 |
203 | # Windows Store app package directories and files
204 | AppPackages/
205 | BundleArtifacts/
206 | Package.StoreAssociation.xml
207 | _pkginfo.txt
208 | *.appx
209 |
210 | # Visual Studio cache files
211 | # files ending in .cache can be ignored
212 | *.[Cc]ache
213 | # but keep track of directories ending in .cache
214 | !?*.[Cc]ache/
215 |
216 | # Others
217 | ClientBin/
218 | ~$*
219 | *~
220 | *.dbmdl
221 | *.dbproj.schemaview
222 | *.jfm
223 | *.pfx
224 | *.publishsettings
225 | orleans.codegen.cs
226 |
227 | # Including strong name files can present a security risk
228 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
229 | #*.snk
230 |
231 | # Since there are multiple workflows, uncomment next line to ignore bower_components
232 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
233 | #bower_components/
234 |
235 | # RIA/Silverlight projects
236 | Generated_Code/
237 |
238 | # Backup & report files from converting an old project file
239 | # to a newer Visual Studio version. Backup files are not needed,
240 | # because we have git ;-)
241 | _UpgradeReport_Files/
242 | Backup*/
243 | UpgradeLog*.XML
244 | UpgradeLog*.htm
245 | ServiceFabricBackup/
246 | *.rptproj.bak
247 |
248 | # SQL Server files
249 | *.mdf
250 | *.ldf
251 | *.ndf
252 |
253 | # Business Intelligence projects
254 | *.rdl.data
255 | *.bim.layout
256 | *.bim_*.settings
257 | *.rptproj.rsuser
258 | *- Backup*.rdl
259 |
260 | # Microsoft Fakes
261 | FakesAssemblies/
262 |
263 | # GhostDoc plugin setting file
264 | *.GhostDoc.xml
265 |
266 | # Node.js Tools for Visual Studio
267 | .ntvs_analysis.dat
268 | node_modules/
269 |
270 | # Visual Studio 6 build log
271 | *.plg
272 |
273 | # Visual Studio 6 workspace options file
274 | *.opt
275 |
276 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
277 | *.vbw
278 |
279 | # Visual Studio LightSwitch build output
280 | **/*.HTMLClient/GeneratedArtifacts
281 | **/*.DesktopClient/GeneratedArtifacts
282 | **/*.DesktopClient/ModelManifest.xml
283 | **/*.Server/GeneratedArtifacts
284 | **/*.Server/ModelManifest.xml
285 | _Pvt_Extensions
286 |
287 | # Paket dependency manager
288 | .paket/paket.exe
289 | paket-files/
290 |
291 | # FAKE - F# Make
292 | .fake/
293 |
294 | # JetBrains Rider
295 | .idea/
296 | *.sln.iml
297 |
298 | # CodeRush personal settings
299 | .cr/personal
300 |
301 | # Python Tools for Visual Studio (PTVS)
302 | __pycache__/
303 | *.pyc
304 |
305 | # Cake - Uncomment if you are using it
306 | # tools/**
307 | # !tools/packages.config
308 |
309 | # Tabs Studio
310 | *.tss
311 |
312 | # Telerik's JustMock configuration file
313 | *.jmconfig
314 |
315 | # BizTalk build output
316 | *.btp.cs
317 | *.btm.cs
318 | *.odx.cs
319 | *.xsd.cs
320 |
321 | # OpenCover UI analysis results
322 | OpenCover/
323 |
324 | # Azure Stream Analytics local run output
325 | ASALocalRun/
326 |
327 | # MSBuild Binary and Structured Log
328 | *.binlog
329 |
330 | # NVidia Nsight GPU debugger configuration file
331 | *.nvuser
332 |
333 | # MFractors (Xamarin productivity tool) working folder
334 | .mfractor/
335 |
336 | # Local History for Visual Studio
337 | .localhistory/
338 |
339 | # BeatPulse healthcheck temp database
340 | healthchecksdb
341 | /ZuAnBot_WinForm
342 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ZuAnBot(祖安助手)
2 | 一键喷人(随机输入骂人语录),可在英雄联盟游戏和客户端中使用。只为反击喷子!欢迎来到祖安。
3 |
4 | 受[祖安宝典](https://github.com/cndiandian/zuanbot.com)启发,想到自己玩LOL经常受喷子的气,还没能力喷回去,于是开发了这个小工具 :smirk:
5 |
6 | # 使用
7 | 从[Latest Release](https://github.com/liuke-wuhan/ZuAnBot/releases/latest)中下载软件:ZuAnBot.exe
8 |
9 | 软件免安装,下载后直接打开即可
10 |
11 | ## 注意
12 | * 注意节制,软件的初心是对付喷子的,不要成为了喷子 :smirk:
13 |
14 | * 不要高频使用,用太多被举报的话可能还是有禁言或封号的风险,我自己用的不是很多,只是被禁言一次,兄弟们被封号可以去[QQ群](https://github.com/liuke-wuhan/ZuAnBot#%E7%A4%BE%E7%BE%A4)或者[Issues](https://github.com/liuke-wuhan/ZuAnBot/issues)上反映一下具体封号的使用场景
15 |
16 | # 社群
17 | * QQ群:
18 |
19 | 
20 |
21 |
22 | # 功能
23 | * 一键喷人
24 | * 自定义词库
25 | * 逐字发送(更安全,绕过屏蔽)
26 |
27 |
28 |
29 | # 截图
30 | 
31 |
32 | 
33 |
34 | 
35 |
36 | 
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/ZuAnBot.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.1.32407.343
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ZuAnBot_Wpf", "ZuAnBot_Wpf\ZuAnBot_Wpf.csproj", "{E72F3F57-8D6C-489F-AA7C-60BCA6C76A13}"
7 | EndProject
8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "解决方案项", "解决方案项", "{14FAFE8E-5E70-440F-9A9A-F178E12B5F94}"
9 | ProjectSection(SolutionItems) = preProject
10 | README.md = README.md
11 | EndProjectSection
12 | EndProject
13 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ZuAnBotUpdate", "ZuAnBotUpdate\ZuAnBotUpdate.csproj", "{C4D7A4E9-F74D-4CA9-997D-07E200176C05}"
14 | EndProject
15 | Global
16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
17 | Debug|Any CPU = Debug|Any CPU
18 | Release|Any CPU = Release|Any CPU
19 | EndGlobalSection
20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
21 | {E72F3F57-8D6C-489F-AA7C-60BCA6C76A13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
22 | {E72F3F57-8D6C-489F-AA7C-60BCA6C76A13}.Debug|Any CPU.Build.0 = Debug|Any CPU
23 | {E72F3F57-8D6C-489F-AA7C-60BCA6C76A13}.Release|Any CPU.ActiveCfg = Release|Any CPU
24 | {E72F3F57-8D6C-489F-AA7C-60BCA6C76A13}.Release|Any CPU.Build.0 = Release|Any CPU
25 | {C4D7A4E9-F74D-4CA9-997D-07E200176C05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
26 | {C4D7A4E9-F74D-4CA9-997D-07E200176C05}.Debug|Any CPU.Build.0 = Debug|Any CPU
27 | {C4D7A4E9-F74D-4CA9-997D-07E200176C05}.Release|Any CPU.ActiveCfg = Release|Any CPU
28 | {C4D7A4E9-F74D-4CA9-997D-07E200176C05}.Release|Any CPU.Build.0 = Release|Any CPU
29 | EndGlobalSection
30 | GlobalSection(SolutionProperties) = preSolution
31 | HideSolutionNode = FALSE
32 | EndGlobalSection
33 | GlobalSection(ExtensibilityGlobals) = postSolution
34 | SolutionGuid = {4F9A81BE-7DC0-4758-8B6E-7607BFE45F16}
35 | EndGlobalSection
36 | EndGlobal
37 |
--------------------------------------------------------------------------------
/ZuAnBotUpdate/Assets/log4net.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/ZuAnBotUpdate/FodyWeavers.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/ZuAnBotUpdate/FodyWeavers.xsd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks
13 |
14 |
15 |
16 |
17 | A list of assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.
18 |
19 |
20 |
21 |
22 | A list of runtime assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks
23 |
24 |
25 |
26 |
27 | A list of runtime assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.
28 |
29 |
30 |
31 |
32 | A list of unmanaged 32 bit assembly names to include, delimited with line breaks.
33 |
34 |
35 |
36 |
37 | A list of unmanaged 64 bit assembly names to include, delimited with line breaks.
38 |
39 |
40 |
41 |
42 | The order of preloaded assemblies, delimited with line breaks.
43 |
44 |
45 |
46 |
47 |
48 | This will copy embedded files to disk before loading them into memory. This is helpful for some scenarios that expected an assembly to be loaded from a physical file.
49 |
50 |
51 |
52 |
53 | Controls if .pdbs for reference assemblies are also embedded.
54 |
55 |
56 |
57 |
58 | Controls if runtime assemblies are also embedded.
59 |
60 |
61 |
62 |
63 | Controls whether the runtime assemblies are embedded with their full path or only with their assembly name.
64 |
65 |
66 |
67 |
68 | Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option.
69 |
70 |
71 |
72 |
73 | As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off.
74 |
75 |
76 |
77 |
78 | Costura by default will load as part of the module initialization. This flag disables that behavior. Make sure you call CosturaUtility.Initialize() somewhere in your code.
79 |
80 |
81 |
82 |
83 | Costura will by default use assemblies with a name like 'resources.dll' as a satellite resource and prepend the output path. This flag disables that behavior.
84 |
85 |
86 |
87 |
88 | A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with |
89 |
90 |
91 |
92 |
93 | A list of assembly names to include from the default action of "embed all Copy Local references", delimited with |.
94 |
95 |
96 |
97 |
98 | A list of runtime assembly names to exclude from the default action of "embed all Copy Local references", delimited with |
99 |
100 |
101 |
102 |
103 | A list of runtime assembly names to include from the default action of "embed all Copy Local references", delimited with |.
104 |
105 |
106 |
107 |
108 | A list of unmanaged 32 bit assembly names to include, delimited with |.
109 |
110 |
111 |
112 |
113 | A list of unmanaged 64 bit assembly names to include, delimited with |.
114 |
115 |
116 |
117 |
118 | The order of preloaded assemblies, delimited with |.
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 | 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
127 |
128 |
129 |
130 |
131 | A comma-separated list of error codes that can be safely ignored in assembly verification.
132 |
133 |
134 |
135 |
136 | 'false' to turn off automatic generation of the XML Schema file.
137 |
138 |
139 |
140 |
141 |
--------------------------------------------------------------------------------
/ZuAnBotUpdate/LogHelper.cs:
--------------------------------------------------------------------------------
1 | using log4net;
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 | using System.Windows;
9 |
10 |
11 | namespace ZuAnBotUpdate
12 | {
13 | public class LogHelper
14 | {
15 | private ILog _logger = null;
16 | public static string logPath;
17 |
18 | public LogHelper(string logDirName = null, string loggerName = "ZuanBot")
19 | {
20 | if (logDirName == null)
21 | InitLogger("ZuanBot", loggerName);
22 | else
23 | {
24 | InitLogger(logDirName, loggerName);
25 | }
26 | }
27 |
28 | public ILog Logger4
29 | {
30 | get { return _logger; }
31 | }
32 |
33 | ///
34 | /// 日志将放入%temp%/CECommonLog文件夹
35 | ///
36 | ///
37 | private void InitLogger(string logDirName, string loggerName)
38 | {
39 | logPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "TEMP", logDirName);
40 | if (!Directory.Exists(logPath)) Directory.CreateDirectory(logPath);
41 | log4net.GlobalContext.Properties["fname"] = Path.Combine(logPath, "log");//日志存放位置
42 |
43 | var stream = ManifestHelper.GetManifestStream("log4net.config");
44 | log4net.Config.XmlConfigurator.Configure(stream);
45 | stream.Close();
46 | //创建一个实例,名字可随便取
47 | _logger = LogManager.GetLogger(loggerName);
48 | _logger.Info("==================初始化Logger====================");
49 | }
50 |
51 | }
52 | }
53 |
54 |
55 |
--------------------------------------------------------------------------------
/ZuAnBotUpdate/ManifestHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Reflection;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace ZuAnBotUpdate
10 | {
11 | ///
12 | /// 清单资源工具类
13 | ///
14 | public static class ManifestHelper
15 | {
16 | public static Stream GetManifestStream(string jsonName)
17 | {
18 | return Assembly.GetExecutingAssembly().GetManifestResourceStream($"ZuAnBotUpdate.Assets.{jsonName}");
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/ZuAnBotUpdate/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.IO;
4 | using System.Linq;
5 |
6 | namespace ZuAnBotUpdate
7 | {
8 | public class Program
9 | {
10 | static void Main(string[] args)
11 | {
12 | var logger = new LogHelper().Logger4;
13 | try
14 | {
15 | logger.Info("进入更新程序args:" + args.Aggregate((a, b) => a + " " + b));
16 | if (args.Length != 2) return;
17 |
18 | var path1 = args[0];
19 | var path2 = args[1];
20 |
21 | if (string.IsNullOrWhiteSpace(path1) || string.IsNullOrWhiteSpace(path2)) return;
22 |
23 | logger.Info($"源:{path1} 目标:{path2}");
24 |
25 | var process = Process.GetProcesses().FirstOrDefault(x=>x.MainWindowTitle=="祖安助手");
26 |
27 | if (process == null || process.MainModule?.FileName != path2)
28 | {
29 | logger.Info($"未找到祖安助手进程");
30 | return;
31 | }
32 |
33 | process.Kill();
34 | process.WaitForExit(1000);
35 | File.Copy(path1, path2, true);
36 |
37 | Process.Start(path2);
38 |
39 | logger.Info("更新程序执行成功");
40 | }
41 | catch (Exception e)
42 | {
43 | logger.Error("更新程序执行出错", e);
44 | }
45 | }
46 | }
47 | }
--------------------------------------------------------------------------------
/ZuAnBotUpdate/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "ZuAnBotUpdate": {
4 | "commandName": "Project",
5 | "commandLineArgs": "C:\\Users\\Admin\\AppData\\Local\\Temp\\祖安助手.exe F:\\work\\LOL\\ZuAnBot\\ZuAnBot_Wpf\\bin\\Release\\net472\\祖安助手.exe"
6 | }
7 | }
8 | }
--------------------------------------------------------------------------------
/ZuAnBotUpdate/ZuAnBotUpdate.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net472
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Api/Apis.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using Newtonsoft.Json;
8 | using Newtonsoft.Json.Linq;
9 | using RestSharp;
10 | using RestSharp.Serializers.NewtonsoftJson;
11 | using ZuAnBot_Wpf.Api.Dtos;
12 | using ZuAnBot_Wpf.Helper;
13 |
14 | namespace ZuAnBot_Wpf.Api
15 | {
16 | public class Apis
17 | {
18 | readonly RestClient _client;
19 |
20 | #region Construct
21 | ///
22 | /// 获取单例
23 | ///
24 | ///
25 | public static Apis GetInstance() => instance;
26 | private static readonly Apis instance = new Apis();
27 | private Apis()
28 | {
29 | try
30 | {
31 | _client = ConstructClient(EnvConfigHelper.Env.UseApi);
32 | }
33 | catch (Exception ex)
34 | {
35 | ex.Show();
36 | }
37 | }
38 | private RestClient ConstructClient(string baseUrl)
39 | {
40 | var client = new RestClient(baseUrl);
41 | client.Options.MaxTimeout = 120000;
42 | client.Options.ThrowOnAnyError = false;
43 |
44 | client.UseNewtonsoftJson(new JsonSerializerSettings
45 | {
46 | NullValueHandling = NullValueHandling.Ignore,
47 | DateFormatString = "yyyy-MM-dd HH:mm:ss"
48 | });
49 | client.AddDefaultHeader("Accept", "application/json");
50 | client.AddDefaultHeader("Content-Type", "application/json");
51 | return client;
52 | }
53 | #endregion Construct
54 |
55 | #region private
56 | ///
57 | /// api响应包装
58 | /// code 编号 200 对应 返回 result code 编号 0 对应 返回 data
59 | ///
60 | ///
61 | class ResultWrapper
62 | {
63 | public int? Code { get; set; }
64 | public string Msg { get; set; }
65 | public T Data { get; set; }
66 | }
67 |
68 | private T HandleResponseOrError(RestResponse> response, RestClient client)
69 | {
70 | var url = (client.Options.BaseUrl + response.Request.Resource).Replace("//", "/");
71 |
72 | if (response.IsSuccessful)
73 | {
74 | if (response.Data.Code == 200)
75 | {
76 | //LkLogHelper.Log.Info($"〔{url}〕请求成功,返回值:〔{JsonConvert.SerializeObject(response.Data.Result)}〕");
77 | return response.Data.Data;
78 | }
79 | else
80 | {
81 | throw new ApiException($"code:{response.Data.Code}\nmessage:{response.Data.Msg}", new Exception($"url:{url}"));
82 | }
83 |
84 | }
85 | else
86 | {
87 | if (response.ContentType == "text/plain")
88 | throw new ApiException($"({(int)response.StatusCode} {response.StatusDescription}){response.Content}", new Exception($"url:{url}"));
89 | else
90 | {
91 | if (response.StatusCode == 0 && response.ErrorMessage == "第 3 行,位置 6 上的开始标记“meta”与结束标记“head”不匹配。 第 107 行,位置 5。")
92 | {
93 | throw new ApiException($"后台服务不可用", new Exception($"url:{url}"));
94 | }
95 | else if (response.StatusCode == 0 && response.ErrorMessage == "The request timed-out.")
96 | {
97 | throw new ApiException($"请求超时", new Exception($"url:{url}"));
98 | }
99 | else
100 | {
101 | throw new ApiException($"({(int)response.StatusCode} {response.StatusDescription}){response.ErrorMessage}", new Exception($"url:{url}"));
102 | }
103 | }
104 |
105 | }
106 | }
107 | #endregion
108 |
109 | ///
110 | /// 文件备份
111 | ///
112 | ///
113 | ///
114 | public async Task Use()
115 | {
116 | var request = new RestRequest("/api/auth/use", Method.Post);
117 |
118 | var response = await _client.ExecuteAsync>(request);
119 |
120 | HandleResponseOrError(response, _client);
121 | }
122 |
123 | ///
124 | /// 获取最新版本
125 | ///
126 | ///
127 | public async Task GetLatestVersion()
128 | {
129 | var request = new RestRequest("/api/versions/latest", Method.Get);
130 |
131 | var response = await _client.ExecuteAsync>(request);
132 |
133 | return HandleResponseOrError(response, _client);
134 | }
135 |
136 | ///
137 | /// 下载文件
138 | ///
139 | /// 目录
140 | /// 文件名
141 | /// url
142 | ///
143 | /// 输入字符串为空
144 | /// 文件下载失败
145 | public string DownloadFile(string dir, string fileName, string fileUrl)
146 | {
147 | if (string.IsNullOrWhiteSpace(fileName)) throw new ArgumentNullException(nameof(fileName));
148 | if (string.IsNullOrWhiteSpace(dir)) throw new ArgumentNullException(nameof(dir));
149 | fileName = Legalize(fileName);
150 | if (string.IsNullOrWhiteSpace(fileName)) throw new ArgumentNullException(nameof(fileName));
151 |
152 | var filePath = Path.Combine(dir, fileName);
153 |
154 | try
155 | {
156 | using (var writer = new ProgressFileStream(filePath, false))
157 | {
158 | var request = new RestRequest(fileUrl);
159 | _client.DownloadStream(request).CopyTo(writer);
160 | }
161 | }
162 | catch (Exception ex)
163 | {
164 | File.Delete(filePath);
165 | throw new Exception($"文件下载失败!请重试\nUrl为:{fileUrl}", ex);
166 | }
167 |
168 | return filePath;
169 | }
170 |
171 | ///
172 | /// 使路径合法化,符合windows文件/文件夹命名规则
173 | ///
174 | ///
175 | ///
176 | private string Legalize(string path)
177 | {
178 | path = path.Replace("\\", "")
179 | .Replace("/", "")
180 | .Replace(":", "")
181 | .Replace("*", "")
182 | .Replace("?", "")
183 | .Replace("\"", "")
184 | .Replace("<", "")
185 | .Replace(">", "")
186 | .Replace("|", "");
187 | return path;
188 | }
189 | }
190 |
191 | ///
192 | /// 后端报错引起的异常
193 | ///
194 | [Serializable]
195 | public class ApiException : Exception
196 | {
197 | public ApiException() { }
198 | public ApiException(string message) : base(message) { }
199 | public ApiException(string message, Exception inner) : base(message, inner) { }
200 | protected ApiException(
201 | System.Runtime.Serialization.SerializationInfo info,
202 | System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
203 | }
204 | }
205 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Api/Dtos/VersionDto.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace ZuAnBot_Wpf.Api.Dtos
8 | {
9 | public class VersionDto
10 | {
11 | public string Url { get; set; } = "";
12 | public string FileName { get; set; } = "";
13 | public string VersionName { get; set; } = "";
14 | public string Description { get; set; } = "";
15 | public DateTime Date { get; set; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/App.xaml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | M827.904 541.184a278.592 278.592 0 0 0 0-58.368l73.728-58.368c15.872-13.056 20.224-35.584 9.728-53.504l-78.592-137.728c-9.984-17.408-31.232-25.856-51.712-18.176l-86.528 35.072c-15.872-11.52-32.512-21.248-49.664-29.184l-12.8-92.928c-3.072-20.224-20.736-35.584-41.216-35.584h-157.44c-20.736 0-38.144 14.848-41.216 35.84L378.88 221.44c-17.152 7.936-33.792 17.92-49.664 29.184L242.688 215.296c-18.688-7.168-41.216 0.768-51.2 18.176L112.64 371.2c-10.24 17.92-6.144 40.448 10.24 53.76l73.472 58.112c-1.024 9.472-1.536 19.2-1.536 29.184 0 9.728 0.512 19.456 1.536 29.184l-73.984 58.368c-15.872 13.056-19.968 35.584-9.728 53.248l78.848 137.728c9.984 17.408 32 25.856 51.456 17.92l86.528-35.072c15.872 11.52 32.512 21.248 49.664 29.184l13.056 93.696c3.328 20.48 20.48 35.328 41.216 35.328h157.44c20.48 0 38.144-15.36 41.216-35.84l13.056-93.184c17.152-7.936 33.792-17.664 49.664-29.184l86.784 35.328c4.864 1.792 9.984 2.816 15.104 2.816 14.848 0 28.672-7.936 36.096-20.992l78.592-137.728c10.24-17.664 6.4-40.192-9.984-53.76l-73.472-58.112z m-25.344 231.168l-99.584-40.448c-7.424-3.072-15.872-1.792-22.272 3.072-19.712 15.36-40.704 27.648-62.464 36.608-7.424 3.072-12.544 9.728-13.568 17.664l-14.592 104.96-155.392 2.304-15.104-107.264c-1.024-7.936-6.4-14.592-13.568-17.664-21.76-8.96-42.752-21.504-62.464-36.608-4.096-3.072-8.96-4.608-13.824-4.608-2.816 0-5.888 0.512-8.448 1.536l-96.256 41.472-80.896-137.216 84.48-66.816c6.144-4.864 9.472-12.8 8.448-20.48-1.536-12.032-2.56-24.32-2.56-36.608 0-12.288 1.024-24.576 2.56-36.608 1.024-7.936-2.048-15.616-8.448-20.48l-83.712-64 76.544-139.264 99.584 40.448c7.424 3.072 15.872 1.792 22.272-3.072 19.712-15.36 40.96-27.648 62.72-36.864 7.424-3.072 12.544-9.728 13.568-17.664l12.544-104.704 157.696-2.304 15.104 107.264c1.024 7.936 6.4 14.592 13.568 17.664 21.76 8.96 42.752 21.504 62.464 36.864 6.4 4.864 14.848 6.144 22.272 3.072l96.256-41.472 80.896 137.216-84.48 66.816c-6.144 4.864-9.472 12.544-8.448 20.48 1.536 12.032 2.56 24.32 2.56 36.608 0 12.288-1.024 24.576-2.56 36.608-1.024 7.936 2.304 15.616 8.448 20.48l83.712 63.744-77.056 139.264zM512 345.6c-91.136 0-165.12 74.752-165.12 166.4s73.984 166.4 165.12 166.4 165.12-74.752 165.12-166.4-73.984-166.4-165.12-166.4z m0 297.216c-71.168 0-129.28-58.624-129.28-130.816 0-72.192 58.112-130.816 129.28-130.816s129.28 58.624 129.28 130.816c0 72.192-57.856 130.816-129.28 130.816z
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.Data;
5 | using System.Linq;
6 | using System.Runtime.InteropServices;
7 | using System.Threading.Tasks;
8 | using System.Windows;
9 | using ImTools;
10 | using Prism.DryIoc;
11 | using Prism.Ioc;
12 | using ZuAnBot_Wpf.Api;
13 | using ZuAnBot_Wpf.Constants;
14 | using ZuAnBot_Wpf.Helper;
15 | using ZuAnBot_Wpf.ViewModels;
16 | using ZuAnBot_Wpf.Views;
17 |
18 | namespace ZuAnBot_Wpf
19 | {
20 | ///
21 | /// App.xaml 的交互逻辑
22 | /// todo:多行词库
23 | ///
24 | public partial class App : PrismApplication
25 | {
26 | public App()
27 | {
28 | try
29 | {
30 | this.Startup += App_Startup;
31 |
32 | //wpf 程序异常捕获,而不崩溃退出
33 | DispatcherUnhandledException += App_DispatcherUnhandledException;
34 | TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
35 | AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
36 | }
37 | catch (Exception e)
38 | {
39 | e.Show();
40 | }
41 | }
42 |
43 | #region 只运行一个程序
44 | [System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:删除未读的私有成员", Justification = "<挂起>")]
45 | private System.Threading.Mutex mutex;
46 | private async void App_Startup(object sender, StartupEventArgs e)
47 | {
48 | try
49 | {
50 | mutex = new System.Threading.Mutex(true, "ZuAnBot_Wpf", out bool ret);
51 |
52 | if (!ret)
53 | {
54 | var handle = Win32Helper.FindWindowEx(IntPtr.Zero, IntPtr.Zero, null, Titles.Main);
55 | IPCHelper.SendMessage("显示", handle);
56 | Environment.Exit(0);
57 | return;
58 | }
59 |
60 | await Apis.GetInstance().Use();
61 | }
62 | catch (ApiException ex)
63 | {
64 | #if DEBUG
65 | ex.Show();
66 | #endif
67 | }
68 | catch (Exception ex)
69 | {
70 | ex.Show();
71 | }
72 | }
73 | #endregion
74 |
75 | protected override Window CreateShell()
76 | {
77 | return Container.Resolve();
78 | }
79 |
80 | protected override void RegisterTypes(IContainerRegistry containerRegistry)
81 | {
82 | containerRegistry.RegisterDialog();
83 | containerRegistry.RegisterDialog();
84 | }
85 |
86 | #region 异常处理
87 | private void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
88 | {
89 | e.SetObserved();
90 | ExceptionHandler(e.Exception.InnerException);
91 | }
92 |
93 | private void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
94 | {
95 | e.Handled = true;
96 | ExceptionHandler(e.Exception);
97 | }
98 |
99 | private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
100 | {
101 | ExceptionHandler((Exception)e.ExceptionObject);
102 | }
103 |
104 | private void ExceptionHandler(Exception ex)
105 | {
106 | Dispatcher.Invoke(() =>
107 | {
108 | ex.Show();
109 | });
110 | }
111 | #endregion
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Assets/Images/QQ.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liuke-wuhan/ZuAnBot/31e695a5c80efa53f354624c2ed530a26c36b96f/ZuAnBot_Wpf/Assets/Images/QQ.png
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Assets/Images/github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liuke-wuhan/ZuAnBot/31e695a5c80efa53f354624c2ed530a26c36b96f/ZuAnBot_Wpf/Assets/Images/github.png
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Assets/Images/lol.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liuke-wuhan/ZuAnBot/31e695a5c80efa53f354624c2ed530a26c36b96f/ZuAnBot_Wpf/Assets/Images/lol.ico
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Assets/Images/删除.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liuke-wuhan/ZuAnBot/31e695a5c80efa53f354624c2ed530a26c36b96f/ZuAnBot_Wpf/Assets/Images/删除.png
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Assets/Images/复制.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liuke-wuhan/ZuAnBot/31e695a5c80efa53f354624c2ed530a26c36b96f/ZuAnBot_Wpf/Assets/Images/复制.png
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Assets/Images/添加.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liuke-wuhan/ZuAnBot/31e695a5c80efa53f354624c2ed530a26c36b96f/ZuAnBot_Wpf/Assets/Images/添加.png
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Assets/Images/祖安.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liuke-wuhan/ZuAnBot/31e695a5c80efa53f354624c2ed530a26c36b96f/ZuAnBot_Wpf/Assets/Images/祖安.ico
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Assets/Images/祖安助手使用交流群群聊二维码.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liuke-wuhan/ZuAnBot/31e695a5c80efa53f354624c2ed530a26c36b96f/ZuAnBot_Wpf/Assets/Images/祖安助手使用交流群群聊二维码.png
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Assets/Images/粘贴.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liuke-wuhan/ZuAnBot/31e695a5c80efa53f354624c2ed530a26c36b96f/ZuAnBot_Wpf/Assets/Images/粘贴.png
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Assets/Images/编辑.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liuke-wuhan/ZuAnBot/31e695a5c80efa53f354624c2ed530a26c36b96f/ZuAnBot_Wpf/Assets/Images/编辑.png
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Assets/Url.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": "prod",
3 | "envs": [
4 | {
5 | "name": "sit",
6 | "useApi": "http://localhost:7286"
7 | },
8 | {
9 | "name": "prod",
10 | "useApi": "http://www.dongdongtuotuo.top:8080"
11 | }
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Assets/log4net.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Assets/wordsLibrary.json:
--------------------------------------------------------------------------------
1 | {
2 | "Categories": [
3 | {
4 | "CategoryName": "默认词库",
5 | "Words": [
6 | {
7 | "Content": "如果思考是生存的证明,我真难判断你是不是一具尸体"
8 | },
9 | {
10 | "Content": "家里哪个亲人去西方极乐净土了?"
11 | },
12 | {
13 | "Content": "你家住海边吗?管这么宽"
14 | },
15 | {
16 | "Content": "掀起你的头盖骨,让我来看看里面的水"
17 | },
18 | {
19 | "Content": "你好像青青草原那个小灰灰,三千多集还是个儿子"
20 | },
21 | {
22 | "Content": "你是不是性無能所以在網上自我高潮找存在感 "
23 | },
24 | {
25 | "Content": "本想和你爸散散步,没想到他先走一步"
26 | },
27 | {
28 | "Content": "你是不是打多了王者荣耀,脑子里也有一个王者峡谷,深不见底?"
29 | },
30 | {
31 | "Content": "你是个孤儿也不能拿这个当借口嗷 懂8?"
32 | },
33 | {
34 | "Content": "你是那青青草原懒羊羊,三千多集顶着翔"
35 | },
36 | {
37 | "Content": "以前你叫斧码,现在你叫斤石"
38 | },
39 | {
40 | "Content": "这么不要脸,这么没心没肺,你的体重应该会很轻吧?"
41 | },
42 | {
43 | "Content": "你要是有病别来找我, 我又不是兽医。"
44 | },
45 | {
46 | "Content": "就是嫉妒我户口本可以翻页(你是孤儿)"
47 | },
48 | {
49 | "Content": "你怕不是吃shi吃多了,一个劲儿的叫我爸爸。"
50 | },
51 | {
52 | "Content": "上帝把智慧洒满人间,就你打了个伞。"
53 | },
54 | {
55 | "Content": "你上辈子一定是个塑料袋 那么会装"
56 | },
57 | {
58 | "Content": "中国那么多兵器你不学,偏学剑!"
59 | },
60 | {
61 | "Content": "十宗罪绝对真实改编。你家谱上的人全是活生生的例子啊!"
62 | },
63 | {
64 | "Content": "我给你妈一扁担打得他不知天上宫阙今夕是何年"
65 | },
66 | {
67 | "Content": "真是让人震惊,犬类排泄物居然也回说话"
68 | },
69 | {
70 | "Content": "能认识自己是个什么东西,都是好样的。"
71 | },
72 | {
73 | "Content": "你脑子不错,可以给老八加口热汤"
74 | },
75 | {
76 | "Content": "你为什么比美团外卖还能送?"
77 | },
78 | {
79 | "Content": "遇到你之前,我的世界是黑白的,遇到你之后,哇靠,全黑了。"
80 | },
81 | {
82 | "Content": "对不起啊,我没有资格骂你神经病,毕竟我不是兽医。"
83 | },
84 | {
85 | "Content": "你这种人永远买不到自己合适的鞋 因为你码没了"
86 | },
87 | {
88 | "Content": "你脑子里的水倒出来是不是当初冲了龙王庙又漫了金山?"
89 | },
90 | {
91 | "Content": "你什么牌的塑料袋 这么能装呢?"
92 | },
93 | {
94 | "Content": "你脖子上顶的是肿瘤吗?"
95 | },
96 | {
97 | "Content": "好家伙,你自己拍全家福挺孤单吧"
98 | },
99 | {
100 | "Content": "平时你爸用你洗衣服吗 我看你像个棒槌"
101 | },
102 | {
103 | "Content": "我今天想骂人 不骂你"
104 | },
105 | {
106 | "Content": "你应该没被蚊子叮过吧,皮真厚"
107 | },
108 | {
109 | "Content": "你和你妈打电话一定要你先挂电话,不然你妈就会挂掉"
110 | },
111 | {
112 | "Content": "网络上你重拳出击,现实中你蹬着三轮车卖鸡"
113 | },
114 | {
115 | "Content": "[转账到账通知]您尾号为1145的储蓄卡收到一笔汇款,金额20,000,000,000元。【天地银行】"
116 | },
117 | {
118 | "Content": "快看天上尼玛在散步"
119 | },
120 | {
121 | "Content": "有病你治病,你别找我啊,我又不是兽医。"
122 | },
123 | {
124 | "Content": "鼠牛虎兔龙蛇羊猴鸡狗猪你自己看看你少了什么"
125 | },
126 | {
127 | "Content": "你不贱不骚不婊,毕竟用来形容人的词,用在你身上不合适"
128 | },
129 | {
130 | "Content": "嫉妒是一种不好的情感,我理解你嫉妒我有家人,可你这么说有点过分了"
131 | },
132 | {
133 | "Content": "你吗在那边缺纸钱了自己去烧别给我叽歪"
134 | },
135 | {
136 | "Content": "这么不要脸,这么没心没肺,你的体重应该会很轻吧?"
137 | },
138 | {
139 | "Content": "希望你打游戏时可以把脑子从粪坑里捞出来带上"
140 | },
141 | {
142 | "Content": "您可真秀,自拍就是族谱"
143 | },
144 | {
145 | "Content": "我是运气多好出门竟然踩了个你"
146 | },
147 | {
148 | "Content": "子不教父之过,你骂人我的错。"
149 | },
150 | {
151 | "Content": " 你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了你急了"
152 | },
153 | {
154 | "Content": "敦煌来的?壁画那么多!"
155 | },
156 | {
157 | "Content": "我希望你能做条好狗不要总像得了狂犬病一样到处咬人"
158 | },
159 | {
160 | "Content": "你没事儿跟我比比啥呢,我又不是吕洞宾"
161 | },
162 | {
163 | "Content": "你知道百度为什么搜不到你吗?你要去搜狗。"
164 | },
165 | {
166 | "Content": "你要么闭嘴,要么藏好你的妈"
167 | },
168 | {
169 | "Content": "十二生肖 鼠牛虎兔龙蛇羊猴鸡狗猪 你看你少了什么?"
170 | },
171 | {
172 | "Content": "看您这逻辑,直肠通大脑吧"
173 | },
174 | {
175 | "Content": "你是老子见过最他妈大的笔盒,装这么多笔不累吗?"
176 | },
177 | {
178 | "Content": "天气转凉,给你妈多穿点,别让她凉了"
179 | },
180 | {
181 | "Content": "回去把宁母亲灰泡水喝,可能心情会好一点😊"
182 | },
183 | {
184 | "Content": "想给你妈献朵花,可是我没花,你也没有妈"
185 | },
186 | {
187 | "Content": "他们怎么就能因为你长的像就说你是猪呢?"
188 | },
189 | {
190 | "Content": "多脏的字骂你我都嫌干净。"
191 | },
192 | {
193 | "Content": "但凡你爸妈当年多唠嗑一分钟 今天也就少了个要分类的垃圾"
194 | },
195 | {
196 | "Content": "长的像人真的难为你了。"
197 | },
198 | {
199 | "Content": "朋友,你要不把你自己的自拍发出来看看,让大伙看看你的全家福有多么幸福?"
200 | },
201 | {
202 | "Content": "你脖子上顶着的是个肿瘤吗"
203 | },
204 | {
205 | "Content": "蛆虫会说话?真是生物学奇迹!"
206 | },
207 | {
208 | "Content": "你棺材板是不是没钉牢 你怎么破土而出了?"
209 | },
210 | {
211 | "Content": "去看猪圈都不用跑趟农村,去你家里就行了。"
212 | },
213 | {
214 | "Content": "别人站着赚钱, 你码躺着。"
215 | },
216 | {
217 | "Content": "你到底是个什么杂交品种,脑仁儿竟然还没瓜子大"
218 | },
219 | {
220 | "Content": "你不去当厨子可惜了,甩锅甩的那么厉害。"
221 | },
222 | {
223 | "Content": "你怎么不在了啊是专门装哑巴上街卖艺了吗可惜你无才无艺二胡捧你手机就断线建议没异能还是不要哑巴恰烂钱"
224 | },
225 | {
226 | "Content": "你在野区刷微信步数?"
227 | },
228 | {
229 | "Content": "仔细看看我这巴掌真适合你那大脸"
230 | },
231 | {
232 | "Content": "您一个阴间的东西,就别指望着能理解咱们阳间的话"
233 | },
234 | {
235 | "Content": "以后不要再说你一无所有了,你不是还有病吗"
236 | },
237 | {
238 | "Content": "开始是网友,后来是你的埋尸人"
239 | },
240 | {
241 | "Content": "我是算命的。请问您算什么东西?"
242 | },
243 | {
244 | "Content": "东边不亮西边亮,憨批啥样你啥样"
245 | },
246 | {
247 | "Content": "每次来拍全家福的时候就只有你一个人"
248 | },
249 | {
250 | "Content": "我想给你妈送朵花,我开玩笑的,毕竟我哪有花,你哪有妈。"
251 | },
252 | {
253 | "Content": "你好像那喜羊羊 三千多集找不着妈"
254 | },
255 | {
256 | "Content": "阁下中午吃奥利给噎着了是怎么的?用为父给你来的稀的溜溜儿缝嘛"
257 | },
258 | {
259 | "Content": "从小妈妈就告诉我,对人要怀有善意,后来我遇到了很多人,明白了不是每一个人都有妈妈。 "
260 | },
261 | {
262 | "Content": "我不由感叹这真是个好时代,因为就连你这种人话都不会说的生物也有权力上网发言。"
263 | },
264 | {
265 | "Content": "你刚才是不是丢东西了, 你脑子不见了。"
266 | },
267 | {
268 | "Content": "wdnmd"
269 | },
270 | {
271 | "Content": "不就是个2,在这儿装什么13"
272 | },
273 | {
274 | "Content": "你看天上你妈在飞,开玩笑的你哪来的妈"
275 | },
276 | {
277 | "Content": "没事多看看天空,你妈可能在看你"
278 | },
279 | {
280 | "Content": "你适合玩庄周,活在梦里"
281 | },
282 | {
283 | "Content": "你傻了吧唧好像我去年路过怡红院的那个老鸨的狗咬死的一只鸡"
284 | },
285 | {
286 | "Content": "豁 什么意思 现在狗也能打字聊天了吗?"
287 | },
288 | {
289 | "Content": "我想啐你一口 又怕你脏了我的唾沫"
290 | },
291 | {
292 | "Content": "你的户口本就是一动物百科"
293 | },
294 | {
295 | "Content": "你的主人是二郎神吧"
296 | },
297 | {
298 | "Content": "我打了狂犬疫苗 你以为我会怕你?"
299 | },
300 | {
301 | "Content": "嘴巴如果闲得慌 不如去公共厕所挨个把马桶舔干净 做个人人称赞的好东西"
302 | },
303 | {
304 | "Content": "天工造物不测,怎么造出你这么个东西"
305 | },
306 | {
307 | "Content": "你的头和蒲公英一样,风一吹,它就秃了"
308 | },
309 | {
310 | "Content": "我刚才给你妈打电话啊,你妈怎么挂了"
311 | },
312 | {
313 | "Content": "你爸妈真会生 好的东西都自己留着"
314 | },
315 | {
316 | "Content": "看到这坨💩🐎,这是你最后的晚餐。"
317 | },
318 | {
319 | "Content": "你是ETC吗 自动抬杠"
320 | },
321 | {
322 | "Content": "我骂人从不扯到你父母 因为他们生了你这么个东西已经够倒霉的了"
323 | },
324 | {
325 | "Content": "赶紧滚吧,在爷面前爬来爬去的晦气玩意"
326 | },
327 | {
328 | "Content": "您这是刚出宫还是刚出土"
329 | },
330 | {
331 | "Content": "这么咄咄逼人 一直没人疼爱缺关注?"
332 | },
333 | {
334 | "Content": "如果梦到你,那真是见鬼。"
335 | },
336 | {
337 | "Content": "别人唱歌要钱,你唱歌要命。"
338 | },
339 | {
340 | "Content": "你做鸭都不配"
341 | },
342 | {
343 | "Content": "我们要向前看,不错过些歪瓜劣枣怎么知道什么是好的。"
344 | },
345 | {
346 | "Content": "真羡慕你一个人就能吃顿团圆饭"
347 | },
348 | {
349 | "Content": "放心吧,不会有富婆看上你的,不过别伤心,也许富婆的狗会看上你,毕竟你长的很符合它的口味。看见你我就想起了我的狗,可惜我不是富婆。"
350 | },
351 | {
352 | "Content": "隔着屏幕就感觉到你那俩眼珠子都离鸡了,眼睛给你算是糟践了,抠出来给我当炮儿踩还能听个响儿"
353 | },
354 | {
355 | "Content": "虽然大脑和大肠长的挺像,但也不要什么都往里面装。对不起,忘了你没大脑。"
356 | },
357 | {
358 | "Content": "我不想和狗吵架。"
359 | },
360 | {
361 | "Content": "你简直浪费你爸妈那仅有两分钟的一晚"
362 | },
363 | {
364 | "Content": "看着你那可悲可笑的滑稽样。我心底产生了一种悲痛感。"
365 | },
366 | {
367 | "Content": "你在你家厕所没吃饱吗"
368 | },
369 | {
370 | "Content": "裤裆里拉二胡,扯卵弹"
371 | },
372 | {
373 | "Content": "今晚我又在你坟头撒了一把白磷,看你的尸体变成烟花于浩瀚星空中绚烂绽放,而我在你坟头载歌载舞疯狂蹦迪。你被洒水车浇灌过的骨灰洋洋洒洒,改善了方圆几里的酸性土壤。"
374 | },
375 | {
376 | "Content": "你好像那懒羊羊 三千多集头顶着坨翔"
377 | },
378 | {
379 | "Content": "不自知的东西,照了镜子也没有用。——钱钟书"
380 | },
381 | {
382 | "Content": "你爸和你妈打电话,你猜谁先挂"
383 | },
384 | {
385 | "Content": "刚好,我QQ农场缺条🐶,我看你不错今天下午就来上班吧"
386 | },
387 | {
388 | "Content": "在?我今晚就把你🐴墓碑掰弯"
389 | },
390 | {
391 | "Content": "最近猪肉涨价了,你是不是也以为自己跟着水涨船高了?"
392 | },
393 | {
394 | "Content": "瞧我这记性,又把你当人看了"
395 | },
396 | {
397 | "Content": "你是不是把敌敌畏当可乐喝了,把你八毛钱十二斤的脑子喝傻了。"
398 | },
399 | {
400 | "Content": "提前给你上柱香,全家走好才像样"
401 | },
402 | {
403 | "Content": "啥比光辉事迹竟然令啥比发出啧啧赞叹正所谓物以类聚人以群分狗以品相遇"
404 | },
405 | {
406 | "Content": "无聊的时候看看天,因为你妈也在天上看你"
407 | },
408 | {
409 | "Content": "你出生的时候是不是被扔起来三次,被接住了两次?"
410 | },
411 | {
412 | "Content": "有空一起上厕所吧,我看你那狗嘴里挺会喷粪的。"
413 | },
414 | {
415 | "Content": "W D N M D"
416 | },
417 | {
418 | "Content": "你脑袋上长个头不是拿来拍皮球的"
419 | },
420 | {
421 | "Content": "你出生的时候是不是把脑子扔了,把胎盘塞脑壳里养大了"
422 | },
423 | {
424 | "Content": "请宁那宛如犬类排泄物的思维器官给老八吃"
425 | },
426 | {
427 | "Content": "为什么不理我 是想让我变成狗不理吗"
428 | },
429 | {
430 | "Content": "赶紧闭嘴吧,你嘴巴直通脑子,一说话我都能看见汪洋大海。"
431 | },
432 | {
433 | "Content": "我把你妈藏起来让你找不到妈"
434 | },
435 | {
436 | "Content": "满手老茧的老撸货凭什么对人家指指点点"
437 | },
438 | {
439 | "Content": "你就是个草履虫,杠吃杠吐的玩意"
440 | },
441 | {
442 | "Content": "你在野区採灵芝呢?"
443 | },
444 | {
445 | "Content": "看见你我就想起了我的狗。"
446 | },
447 | {
448 | "Content": "如果愚蠢有质量,许多人早已变成黑洞"
449 | },
450 | {
451 | "Content": "深圳禁止食狗肉了,原来是在保护你和你全家啊😃 "
452 | },
453 | {
454 | "Content": "本大爹将你这弱智小儿一手击在墙上抠都抠不下来"
455 | },
456 | {
457 | "Content": "你是野草成了精,兜兜转转找不着母亲?"
458 | },
459 | {
460 | "Content": "您还没出殡呢?"
461 | },
462 | {
463 | "Content": "你的嘴简直能给农田施肥"
464 | },
465 | {
466 | "Content": "现在脑瘫复健医院也联网了吗,怎么康复期的病人都出来恶心人了"
467 | },
468 | {
469 | "Content": "别对着我叫,我小时候被狗吓过。"
470 | },
471 | {
472 | "Content": "你是莎士比亚没有士"
473 | },
474 | {
475 | "Content": "你妈为了阻止你谈恋爱竟然给了你这张脸。"
476 | },
477 | {
478 | "Content": "👴 专业配钥匙,这是官方的许可,恁配吗?哦,恁不配哦。啥?恁配?那恁配几把?"
479 | },
480 | {
481 | "Content": "你长脑袋只是为了让自己看起来高一点吧。对不起,我忘了你没有脑袋,又戳到你的伤心出了吧!你脖子上顶的不是肿瘤,而是水泡,看起来是个肉瘤,其实一戳水直流。"
482 | },
483 | {
484 | "Content": "你怕不是一条蚯蚓,脸和屁股长的一样。"
485 | },
486 | {
487 | "Content": "你怎么跟美羊羊一样3000多集了还找不到妈🙂"
488 | },
489 | {
490 | "Content": "不错嘛,年纪轻轻就知道用脸吓唬人"
491 | },
492 | {
493 | "Content": "你在这逼逼赖赖这么久,看中哪块坟墓是你的?"
494 | },
495 | {
496 | "Content": "年少不知🐴珍贵,老来对坟空流泪"
497 | },
498 | {
499 | "Content": "每个人都有妈妈,而你就不一样了,你不是人"
500 | },
501 | {
502 | "Content": "你是我见过的容量最大的铅笔盒了,装那么多笔你不累吗?"
503 | },
504 | {
505 | "Content": "你真对不起你爸妈辛苦的那一晚"
506 | },
507 | {
508 | "Content": "今天想骂人 所以不骂你"
509 | },
510 | {
511 | "Content": "刚从厕所出来,好歹先把嘴擦擦干净"
512 | },
513 | {
514 | "Content": "别光喝酒吃点头孢"
515 | },
516 | {
517 | "Content": "你户口本单页的呢嘚瑟个啥"
518 | },
519 | {
520 | "Content": "苍蝇走在你脸上都崴脚"
521 | },
522 | {
523 | "Content": "你再这样说你🐴 的追悼会我就不去了"
524 | },
525 | {
526 | "Content": "你很擅长魔术吗?变畜生变得挺厉害的"
527 | },
528 | {
529 | "Content": "你打字这么慢是在查新华字典吗🐶 "
530 | },
531 | {
532 | "Content": "脑瘫只能是脑瘫,毕竟医学都救不了你"
533 | },
534 | {
535 | "Content": "长城要是用你脸皮做的 孟姜女能哭倒才怪"
536 | },
537 | {
538 | "Content": "xswl穷酸废物真把自己当条贵宾犬了搁着叫唤你🐎呢"
539 | },
540 | {
541 | "Content": "你长脑袋只是为了让自己看起来高一点吧"
542 | },
543 | {
544 | "Content": "我留你狗命是因为我想保护动物毕竟你做只狗不容易"
545 | },
546 | {
547 | "Content": "你的户口簿上只有一位吗?"
548 | },
549 | {
550 | "Content": "您好可怜,有人生,有人养,没人教的野孩子"
551 | },
552 | {
553 | "Content": "很心疼你,大家都是人,就你一个畜牲,越努力想当个人越可怜"
554 | },
555 | {
556 | "Content": "咋滴你管那么多呢?收粪车从你家门前路过你都要拿勺子尝尝咸淡?"
557 | },
558 | {
559 | "Content": "不必自卑,虽然你智商方面和我的差距就像是我和爱因斯坦,但你的户口本所占用的空间比我少一大坨"
560 | },
561 | {
562 | "Content": "你就像那美羊羊,三千集找不到娘"
563 | },
564 | {
565 | "Content": "认了二郎神做主人就开始乱叫?"
566 | },
567 | {
568 | "Content": "跟混畜生道的人讲人道是行不通的。"
569 | },
570 | {
571 | "Content": "以后打电话记得让别人先挂 不然你就挂了"
572 | },
573 | {
574 | "Content": "你说话咋这么臭呢?嘴里长痔疮了?"
575 | },
576 | {
577 | "Content": "我见过脑袋有洞的,就没见过比你洞还多的,呀呀呀,可别动,脑壳里的水晃出来真TM像个花洒"
578 | },
579 | {
580 | "Content": "我这聊着聊着还有点饿了呢 emmm想拿你骨灰熬点稀饭"
581 | },
582 | {
583 | "Content": "你是不是掉过粪坑里,脖子以上全截肢了?"
584 | },
585 | {
586 | "Content": "垃圾都有家,你却没有。"
587 | },
588 | {
589 | "Content": "人不犯我我不犯人 人若犯我 我挖你祖坟"
590 | },
591 | {
592 | "Content": "你永远都不能用尿滋醒一个张开嘴接的人"
593 | },
594 | {
595 | "Content": "我没病,你没礼貌,让我们原谅彼此的不完美好吗?"
596 | },
597 | {
598 | "Content": "完了,你不理我,我成狗不理了!"
599 | },
600 | {
601 | "Content": "你在无中生有 你在暗度陈仓 你在凭空想象 你在凭空捏造 你在无言无语 你在无可救药 你是逝者安息 你是一路走好 你是傻子巴拉 你是永无止境 你是没钱买药 你是头脑有病 你是眼里有泡 你是嘴里刘能 你是污言秽语 你是咎由自取 你是殃及无辜 你是祸害众生 你是仓皇失措 你是暗度陈仓 你是无可救药"
602 | },
603 | {
604 | "Content": "有空一起上厕所 我看你嘴很会喷shi"
605 | },
606 | {
607 | "Content": "看你这么凶,我的qq农场缺只狗,明天来上班"
608 | },
609 | {
610 | "Content": "知道为什么一会说你有🐴 一会说你没🐴 吗?因为你🐴 是薛定谔的🐴,👴 我一观测,你🐴就坍缩没了 "
611 | },
612 | {
613 | "Content": "想必阁下就是东莞站街劳模吧"
614 | },
615 | {
616 | "Content": "这是第一次当你的老爸,我们的心情都有点复杂"
617 | },
618 | {
619 | "Content": "你是数字界和字母界的二把手"
620 | },
621 | {
622 | "Content": "别半夜翻箱想不开了。今天你爹我就说你到这了"
623 | },
624 | {
625 | "Content": "你看上去好眼熟 像我昨天扔出去的那袋垃圾"
626 | },
627 | {
628 | "Content": "扔块肉在键盘上,狗都比你会连招。"
629 | },
630 | {
631 | "Content": "请问芋泥玛奇朵还要加热吗?因为泥玛凉了"
632 | },
633 | {
634 | "Content": "你慢点说,我狗语不是很好"
635 | },
636 | {
637 | "Content": "不用您付钱不用您费力,刚好我人缘好,马上就给您雇团队来个至尊级别的黑人抬棺,音乐呢就放今天是个好日子,棺材咱们也不封严实了,让你听听大家的乐呵声"
638 | },
639 | {
640 | "Content": "虽然你没对象,但你一个人就是狗粮。"
641 | },
642 | {
643 | "Content": "你爸妈可真会生,好的东西都自个留着"
644 | },
645 | {
646 | "Content": "大年初一你全家在奈何桥上看烟花"
647 | },
648 | {
649 | "Content": "以前我还可以纵容你,但是在辣鸡分类后你只能呆这了。"
650 | },
651 | {
652 | "Content": "以前你叫李闯 后来你改名叫李门"
653 | },
654 | {
655 | "Content": "真羡慕他这种身份证拿出来就是全家福的人"
656 | },
657 | {
658 | "Content": "真好啊 你出生就是户主"
659 | },
660 | {
661 | "Content": "你就是那野草成了精,兜兜转转找不到母亲"
662 | },
663 | {
664 | "Content": "你嘴在化粪池都泡开花了"
665 | },
666 | {
667 | "Content": "几个马呢说话这么嚣张"
668 | },
669 | {
670 | "Content": "杨戬喊你呢!"
671 | },
672 | {
673 | "Content": "咋了?怂了?怂了就把宁那宛如犬类排泄物的思维器官给老八吃"
674 | },
675 | {
676 | "Content": "你是敦煌来的吧?逼话这么多。"
677 | },
678 | {
679 | "Content": "小嘴抹了开塞露似的,总往外喷"
680 | },
681 | {
682 | "Content": "你的人生,总结起来就八个字儿——生的荒唐,死的窝囊🙊"
683 | },
684 | {
685 | "Content": "说你蠢,你还真把自己当猪"
686 | },
687 | {
688 | "Content": "我看你嘴挺能说的 能帮我暖暖脚么"
689 | },
690 | {
691 | "Content": "网络上你重拳出击,现实中你蹬着三轮卖鸡"
692 | },
693 | {
694 | "Content": "天上星星亮晶晶 好像你妈眨眼睛"
695 | },
696 | {
697 | "Content": "天凉了,你妈也凉了"
698 | },
699 | {
700 | "Content": "粪车打你家门口过你都得尝尝咸淡呢"
701 | }
702 | ]
703 | },
704 | {
705 | "CategoryName": "自定义词库",
706 | "Words": []
707 | }
708 | ]
709 | }
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Constants/DialogTokens.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace ZuAnBot_Wpf.Constants
8 | {
9 | public static class DialogTokens
10 | {
11 | public const string MainWindow = nameof(MainWindow);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Constants/Events/Events.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Prism.Events;
7 |
8 | namespace ZuAnBot_Wpf.Constants.Events
9 | {
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Constants/Params.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace ZuAnBot_Wpf.Constants
8 | {
9 | public static class Params
10 | {
11 | public static readonly string Library = nameof(Library);
12 | public static readonly string WordContent = nameof(WordContent);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Constants/Titles.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace ZuAnBot_Wpf.Constants
8 | {
9 | public static class Titles
10 | {
11 | public static readonly string Main = "祖安助手";
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/FodyWeavers.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/FodyWeavers.xsd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks
13 |
14 |
15 |
16 |
17 | A list of assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.
18 |
19 |
20 |
21 |
22 | A list of runtime assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks
23 |
24 |
25 |
26 |
27 | A list of runtime assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.
28 |
29 |
30 |
31 |
32 | A list of unmanaged 32 bit assembly names to include, delimited with line breaks.
33 |
34 |
35 |
36 |
37 | A list of unmanaged 64 bit assembly names to include, delimited with line breaks.
38 |
39 |
40 |
41 |
42 | The order of preloaded assemblies, delimited with line breaks.
43 |
44 |
45 |
46 |
47 |
48 | This will copy embedded files to disk before loading them into memory. This is helpful for some scenarios that expected an assembly to be loaded from a physical file.
49 |
50 |
51 |
52 |
53 | Controls if .pdbs for reference assemblies are also embedded.
54 |
55 |
56 |
57 |
58 | Controls if runtime assemblies are also embedded.
59 |
60 |
61 |
62 |
63 | Controls whether the runtime assemblies are embedded with their full path or only with their assembly name.
64 |
65 |
66 |
67 |
68 | Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option.
69 |
70 |
71 |
72 |
73 | As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off.
74 |
75 |
76 |
77 |
78 | Costura by default will load as part of the module initialization. This flag disables that behavior. Make sure you call CosturaUtility.Initialize() somewhere in your code.
79 |
80 |
81 |
82 |
83 | Costura will by default use assemblies with a name like 'resources.dll' as a satellite resource and prepend the output path. This flag disables that behavior.
84 |
85 |
86 |
87 |
88 | A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with |
89 |
90 |
91 |
92 |
93 | A list of assembly names to include from the default action of "embed all Copy Local references", delimited with |.
94 |
95 |
96 |
97 |
98 | A list of runtime assembly names to exclude from the default action of "embed all Copy Local references", delimited with |
99 |
100 |
101 |
102 |
103 | A list of runtime assembly names to include from the default action of "embed all Copy Local references", delimited with |.
104 |
105 |
106 |
107 |
108 | A list of unmanaged 32 bit assembly names to include, delimited with |.
109 |
110 |
111 |
112 |
113 | A list of unmanaged 64 bit assembly names to include, delimited with |.
114 |
115 |
116 |
117 |
118 | The order of preloaded assemblies, delimited with |.
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 | 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
127 |
128 |
129 |
130 |
131 | A comma-separated list of error codes that can be safely ignored in assembly verification.
132 |
133 |
134 |
135 |
136 | 'false' to turn off automatic generation of the XML Schema file.
137 |
138 |
139 |
140 |
141 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Helper/EnvConfigs.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace ZuAnBot_Wpf.Helper
8 | {
9 | public class Env
10 | {
11 | ///
12 | /// 环境名
13 | ///
14 | public string Name { get; set; }
15 |
16 | ///
17 | ///
18 | ///
19 | public string UseApi { get; set; }
20 | }
21 |
22 | public class EnvConfigs
23 | {
24 | ///
25 | /// 当前环境
26 | ///
27 | public string Env { get; set; }
28 |
29 | ///
30 | /// 环境配置列表
31 | ///
32 | public List Envs { get; set; }
33 | }
34 |
35 | public static class EnvConfigHelper
36 | {
37 | private static readonly string JsonFile = "Url.json";
38 |
39 | public static Env Env
40 | {
41 | get
42 | {
43 | var configs = JsonHelper.DeserializeManifestJson(JsonFile);
44 |
45 | return configs.Envs.FirstOrDefault(x => x.Name == configs.Env) ?? throw new Exception($"不存在配置环境:{configs.Env}");
46 | }
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Helper/ExceptionExtension.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net.Http;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using System.Windows;
8 | using HandyControl.Controls;
9 | using ZuAnBot_Wpf.Api;
10 | using MessageBox = HandyControl.Controls.MessageBox;
11 |
12 | namespace ZuAnBot_Wpf.Helper
13 | {
14 | public static class ExceptionExtension
15 | {
16 | ///
17 | /// 获取错误描述
18 | ///
19 | ///
20 | ///
21 | public static string GetDescription(this Exception ex)
22 | {
23 | return GetDescriptionInternal(ex);
24 | }
25 |
26 | private static string GetDescriptionInternal(Exception ex, int n = 1)
27 | {
28 | string innerError = "";
29 | if (ex.InnerException != null && n < 5)
30 | {
31 | var innerDesc = GetDescriptionInternal(ex.InnerException, ++n);
32 | innerError = $"\n--- 内部错误 ---\n:{innerDesc}";
33 | }
34 |
35 | return $"{ex.GetSourceDesc()}{ex.Message}\n[{ex.GetType().FullName}]调用堆栈:\n{ex.StackTrace}{innerError}";
36 | }
37 |
38 | ///
39 | /// 描述异常来源,是后端还是客户端
40 | ///
41 | ///
42 | ///
43 | public static string GetSourceDesc(this Exception ex)
44 | {
45 | if (ex is ApiException)
46 | {
47 | return "[服务器异常]";
48 | }
49 | else if(ex is HttpRequestException)
50 | {
51 | return "[服务器异常]";
52 | }
53 | else
54 | {
55 | return "[客户端异常]";
56 | }
57 | }
58 |
59 | ///
60 | /// 通过messagebox弹出错误
61 | ///
62 | ///
63 | public static void Show(this Exception e, string msg = "", bool showDetail = true)
64 | {
65 | if (!string.IsNullOrWhiteSpace(msg))
66 | msg += "\n";
67 |
68 | if (showDetail)
69 | msg += e.GetDescription();
70 | else
71 | msg += e.Message;
72 |
73 | LogHelper.Log.Error(msg);
74 |
75 | MessageHelper.Error(msg);
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Helper/GlobalKeyboardHook.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Runtime.CompilerServices;
7 | using System.Runtime.InteropServices;
8 | using System.Threading;
9 | using System.Windows.Forms;
10 |
11 | namespace ZuAnBot_Wpf.Helper
12 | {
13 | public class GlobalKeyboardHook
14 | {
15 | private const int WH_KEYBOARD_LL = 13;
16 |
17 | private const int WM_KEYDOWN = 256;
18 |
19 | private const int WM_KEYUP = 257;
20 |
21 | private const int WM_SYSKEYDOWN = 260;
22 |
23 | private const int WM_SYSKEYUP = 261;
24 |
25 | private GlobalKeyboardHook.LLKeyboardHook llkh;
26 |
27 | public List HookedKeys = new List();
28 |
29 | private IntPtr Hook = IntPtr.Zero;
30 |
31 | public GlobalKeyboardHook()
32 | {
33 | this.llkh = new GlobalKeyboardHook.LLKeyboardHook(this.HookProc);
34 | }
35 |
36 | [DllImport("user32.dll", CharSet = CharSet.None, ExactSpelling = false)]
37 | private static extern int CallNextHookEx(IntPtr hhk, int code, int wParam, ref GlobalKeyboardHook.keyBoardHookStruct lParam);
38 |
39 | ~GlobalKeyboardHook()
40 | {
41 | this.unhook();
42 | }
43 |
44 | public void hook()
45 | {
46 | IntPtr hInstance = GlobalKeyboardHook.LoadLibrary("User32");
47 | this.Hook = GlobalKeyboardHook.SetWindowsHookEx(13, this.llkh, hInstance, 0);
48 | }
49 |
50 | public int HookProc(int Code, int wParam, ref GlobalKeyboardHook.keyBoardHookStruct lParam)
51 | {
52 | if (Code >= 0)
53 | {
54 | Keys key = (Keys)lParam.vkCode;
55 | if (this.HookedKeys.Contains(key))
56 | {
57 | KeyEventArgs kArg = new KeyEventArgs(key);
58 | if ((wParam == 256 || wParam == 260) && this.KeyDown != null)
59 | {
60 | this.KeyDown(this, kArg);
61 | }
62 | else if ((wParam == 257 || wParam == 261) && this.KeyUp != null)
63 | {
64 | this.KeyUp(this, kArg);
65 | }
66 | if (kArg.Handled)
67 | {
68 | return 1;
69 | }
70 | }
71 | }
72 | return GlobalKeyboardHook.CallNextHookEx(this.Hook, Code, wParam, ref lParam);
73 | }
74 |
75 | [DllImport("kernel32.dll", CharSet = CharSet.None, ExactSpelling = false)]
76 | private static extern IntPtr LoadLibrary(string lpFileName);
77 |
78 | [DllImport("user32.dll", CharSet = CharSet.None, ExactSpelling = false)]
79 | private static extern IntPtr SetWindowsHookEx(int idHook, GlobalKeyboardHook.LLKeyboardHook callback, IntPtr hInstance, uint theardID);
80 |
81 | public void unhook()
82 | {
83 | GlobalKeyboardHook.UnhookWindowsHookEx(this.Hook);
84 | }
85 |
86 | [DllImport("user32.dll", CharSet = CharSet.None, ExactSpelling = false)]
87 | private static extern bool UnhookWindowsHookEx(IntPtr hInstance);
88 |
89 | public event KeyEventHandler KeyDown;
90 |
91 | public event KeyEventHandler KeyUp;
92 |
93 | public struct keyBoardHookStruct
94 | {
95 | public int vkCode;
96 |
97 | public int scanCode;
98 |
99 | public int flags;
100 |
101 | public int time;
102 |
103 | public int dwExtraInfo;
104 | }
105 |
106 | public delegate int LLKeyboardHook(int Code, int wParam, ref GlobalKeyboardHook.keyBoardHookStruct lParam);
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Helper/IPCHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Runtime.InteropServices;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using System.Windows;
8 | using System.Windows.Forms;
9 | using System.Windows.Interop;
10 |
11 | namespace ZuAnBot_Wpf.Helper
12 | {
13 | public class IPCHelper
14 | {
15 | ///
16 | /// 通过IPC发送消息到其他线程
17 | ///
18 | /// 字符串消息
19 | /// 目标窗口句柄
20 | public static void SendMessage(string s, IntPtr hWnd)
21 | {
22 | if (hWnd == null) return;
23 |
24 | byte[] sarr = Encoding.Default.GetBytes(s);
25 | int len = sarr.Length;
26 | CopyData cds2;
27 | cds2.dwData = (IntPtr)0;
28 | cds2.cbData = len + 1;
29 | cds2.lpData = s;
30 |
31 | // 发送消息
32 | SendMessage(hWnd, WM_COPYDATA, IntPtr.Zero, ref cds2);
33 | }
34 |
35 | private static Action _handler;
36 | public static void ObserveMessage(Window window, Action handler)
37 | {
38 | _handler = handler;
39 |
40 | HwndSource hwndSource = PresentationSource.FromVisual(window) as HwndSource;
41 | if (hwndSource != null)
42 | {
43 | IntPtr handle = hwndSource.Handle;
44 | hwndSource.AddHook(new HwndSourceHook(WndProc));
45 | }
46 | }
47 | private static IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
48 | {
49 | if (msg == WM_COPYDATA)
50 | {
51 | //int value = wParam.ToInt32();
52 | //var enumValue = (string)(object)value;
53 |
54 | CopyData cds = (CopyData)Marshal.PtrToStructure(lParam, typeof(CopyData));
55 |
56 | // 自定义行为
57 | var message = cds.lpData;
58 | _handler.Invoke(message);
59 | }
60 | return hwnd;
61 | }
62 |
63 | [DllImport("User32.dll", EntryPoint = "SendMessage")]
64 | private static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, ref CopyData lParam);
65 | public const int WM_COPYDATA = 0x004A; // 固定数值,不可更改
66 |
67 | }
68 |
69 | struct CopyData
70 | {
71 | public IntPtr dwData; // 任意值
72 | public int cbData; // 指定lpData内存区域的字节数
73 | [MarshalAs(UnmanagedType.LPStr)]
74 | public string lpData; // 发送给目标窗口所在进程的数据
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Helper/JsonHelper.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System.IO;
3 | using System.Linq;
4 | using ZuAnBot_Wpf.ViewModels;
5 |
6 | namespace ZuAnBot_Wpf.Helper
7 | {
8 | ///
9 | /// json持久化工具类
10 | ///
11 | public static class JsonHelper
12 | {
13 | public static T DeserializeManifestJson(string jsonName)
14 | {
15 | var stream = ManifestHelper.GetManifestStream(jsonName);
16 |
17 | return DeserializeStream(stream);
18 | }
19 |
20 | ///
21 | /// 反序列化词库
22 | ///
23 | ///
24 | public static WordsLibrary DeserializeWordsLibrary()
25 | {
26 | using (var stream = new FileStream(LocalConfigHelper.WordsLibraryPath, FileMode.Open))
27 | {
28 | #region 给word的category导航属性赋值
29 | var libray = DeserializeStream(stream);
30 | foreach (var category in libray.Categories)
31 | {
32 | category.TargetCategories = libray.Categories.Where(x => x != category).ToList();
33 |
34 | category.Library = libray;
35 |
36 | foreach (var word in category.Words)
37 | {
38 | word.Category = category;
39 | }
40 | }
41 |
42 | #endregion 给word的category导航属性赋值
43 |
44 | return libray;
45 | }
46 | }
47 |
48 | ///
49 | /// 序列化词库
50 | ///
51 | ///
52 | public static void SerializeWordsLibrary(WordsLibrary library)
53 | {
54 | if (library == null) return;
55 |
56 | var tempfile = Path.GetTempFileName();
57 | using (var streamWritter = File.CreateText(tempfile))
58 | {
59 | JsonSerializer serializer = new JsonSerializer();
60 | serializer.Serialize(streamWritter, library);
61 | }
62 |
63 | File.Copy(tempfile, LocalConfigHelper.WordsLibraryPath, true);
64 | }
65 |
66 | private static T DeserializeStream(Stream stream)
67 | {
68 | StreamReader reader = new StreamReader(stream);
69 | JsonSerializer serializer = new JsonSerializer();
70 | return (T)serializer.Deserialize(reader, typeof(T));
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Helper/LocalConfigHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace ZuAnBot_Wpf.Helper
9 | {
10 | ///
11 | /// 本地配置文件
12 | ///
13 | public class LocalConfigHelper
14 | {
15 | private static readonly string wordsLibraryFile = "wordsLibrary.json";
16 |
17 | ///
18 | /// 配置文件目录
19 | ///
20 | public static string Dir => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "ZuAnBot");
21 |
22 | ///
23 | /// 词库文件路径
24 | ///
25 | public static string WordsLibraryPath => GetPath(wordsLibraryFile);
26 |
27 | ///
28 | /// 获取配置文件路径
29 | ///
30 | ///
31 | ///
32 | public static string GetPath(string configFileName)
33 | {
34 | return Path.Combine(Dir, configFileName);
35 | }
36 |
37 |
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Helper/LogHelper.cs:
--------------------------------------------------------------------------------
1 | using log4net;
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 | using System.Windows;
9 |
10 |
11 | namespace ZuAnBot_Wpf.Helper
12 | {
13 | public static class LogHelper
14 | {
15 | private static ILog _logger = null;
16 | public static string logPath;
17 |
18 | static LogHelper()
19 | {
20 | InitLogger("ZuanBot", "ZuanBot");
21 | }
22 |
23 | ///
24 | /// 若没初始化,日志将放入%temp%\ZuanBot文件夹
25 | ///
26 | public static ILog Log
27 | {
28 | get { return _logger; }
29 | }
30 |
31 | ///
32 | /// 初始化日志存放位置,若不初始化则存放在%temp%\ZuanBot
33 | ///
34 | ///
35 | private static void InitLogger(string logDirName, string loggerName)
36 | {
37 | logPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "TEMP", logDirName);
38 | if (!Directory.Exists(logPath)) Directory.CreateDirectory(logPath);
39 | log4net.GlobalContext.Properties["fname"] = Path.Combine(logPath, "log");//日志存放位置
40 |
41 | var stream = ManifestHelper.GetManifestStream("log4net.config");
42 | log4net.Config.XmlConfigurator.Configure(stream);
43 | stream.Close();
44 | //创建一个实例,名字可随便取
45 | _logger = LogManager.GetLogger(loggerName);
46 | _logger.Info("==================初始化Logger====================");
47 | }
48 |
49 | }
50 | }
51 |
52 |
53 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Helper/ManifestHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Reflection;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace ZuAnBot_Wpf.Helper
10 | {
11 | ///
12 | /// 清单资源工具类
13 | ///
14 | public static class ManifestHelper
15 | {
16 | public static Stream GetManifestStream(string jsonName)
17 | {
18 | return Assembly.GetExecutingAssembly().GetManifestResourceStream($"ZuAnBot_Wpf.Assets.{jsonName}");
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Helper/MessageHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 |
8 | namespace ZuAnBot_Wpf.Helper
9 | {
10 | public static class MessageHelper
11 | {
12 | public static void Error(string msg)
13 | {
14 | MessageBox.Show(msg, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
15 | }
16 |
17 | public static void Info(string msg)
18 | {
19 | MessageBox.Show(msg, "通知", MessageBoxButton.OK, MessageBoxImage.Information);
20 | }
21 |
22 | ///
23 | /// 警告并询问用户是否继续
24 | ///
25 | ///
26 | /// 是否继续
27 | public static bool Warning(string msg)
28 | {
29 | return MessageBox.Show(msg, "警告", MessageBoxButton.OKCancel, MessageBoxImage.Warning) == MessageBoxResult.OK;
30 | }
31 |
32 | ///
33 | /// 询问用户是否继续
34 | ///
35 | ///
36 | /// 是否继续
37 | public static bool Question(string msg)
38 | {
39 | return MessageBox.Show(msg, "", MessageBoxButton.OKCancel, MessageBoxImage.Question) == MessageBoxResult.OK;
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Helper/ProgressFileStream.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace ZuAnBot_Wpf.Helper
9 | {
10 | ///
11 | /// 可以记录传输进度的文件流
12 | ///
13 | public class ProgressFileStream : FileStream
14 | {
15 | ///
16 | ///
17 | ///
18 | ///
19 | /// true为上传流,false为下载流
20 | public ProgressFileStream(string path, bool isRead) : base(path, isRead ? FileMode.Open : FileMode.Create, isRead ? FileAccess.Read : FileAccess.Write)
21 | {
22 | }
23 |
24 | public long CurrentSize { get; private set; }
25 |
26 |
27 | ///
28 | /// 流的传输监控器
29 | ///
30 | public event EventHandler Progress;
31 |
32 | public override void Write(byte[] array, int offset, int count)
33 | {
34 | base.Write(array, offset, count);
35 |
36 | CurrentSize += count;
37 | if (Progress != null)
38 | Progress(this, new FileEventArgs(CurrentSize, Length));
39 | }
40 |
41 | public override int Read(byte[] array, int offset, int count)
42 | {
43 | int res = base.Read(array, offset, count);
44 |
45 | CurrentSize += count;
46 | if (Progress != null)
47 | Progress(this, new FileEventArgs(CurrentSize, Length));//上传进度
48 |
49 | return res;
50 | }
51 | }
52 |
53 | public class FileEventArgs : EventArgs
54 | {
55 | public FileEventArgs(long currentSize, long totalSize)
56 | {
57 | CurrentSize = currentSize;
58 | TotalSize = totalSize;
59 | }
60 |
61 | public long CurrentSize { get; }
62 | public long TotalSize { get; }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Helper/VersionHelper.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.Threading.Tasks;
7 | using ZuAnBot_Wpf.Api;
8 | using ZuAnBot_Wpf.Api.Dtos;
9 |
10 | namespace ZuAnBot_Wpf.Helper
11 | {
12 | public static class VersionHelper
13 | {
14 | private static readonly Apis _apis = Apis.GetInstance();
15 | private readonly static string _pattern = @"^[0-9]{1,2}\.[0-9]{1,2}\.[0-9]{1,2}$";
16 |
17 | ///
18 | /// 获取最新版本
19 | ///
20 | ///
21 | public static async Task GetLatestVersion()
22 | {
23 | try
24 | {
25 | return await _apis.GetLatestVersion();
26 | }
27 | catch (ApiException)
28 | {
29 | return null;
30 | }
31 | }
32 |
33 | ///
34 | /// 获取当前版本名称
35 | ///
36 | ///
37 | public static string GetCurrentVersionName()
38 | {
39 | return System.Windows.Application.ResourceAssembly.GetName().Version.ToString(3);
40 | }
41 |
42 | ///
43 | /// 输入后端最新版本信息,判断当前版本是否是最新版本
44 | ///
45 | ///
46 | ///
47 | public static bool IsNewestVersion(VersionDto latestVersion)
48 | {
49 | if (latestVersion == null) return true;
50 |
51 | var currentVersionName = GetCurrentVersionName();
52 |
53 | return CompareVersion(currentVersionName, latestVersion.VersionName) >= 0;
54 | }
55 |
56 | ///
57 | /// 比较两个版本号
58 | ///
59 | ///
60 | ///
61 | /// v1小于v2则返回-1,v1等于v2返回0,v1大于v2返回1
62 | ///
63 | public static int CompareVersion(string v1, string v2)
64 | {
65 | if (!Regex.IsMatch(v1, _pattern) || !Regex.IsMatch(v2, _pattern))
66 | {
67 | throw new ArgumentOutOfRangeException("指定版本号格式无效");
68 | }
69 |
70 | var version1 = v1.Split('.').Select(int.Parse).ToArray();
71 | var version2 = v2.Split('.').Select(int.Parse).ToArray();
72 |
73 | for (int i = 0; i < 3; i++)
74 | {
75 | if (version1[i] > version2[i])
76 | return 1;
77 | else if (version1[i] < version2[i])
78 | return -1;
79 | }
80 |
81 | return 0;
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Helper/Win32Helper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Linq;
5 | using System.Runtime.InteropServices;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using System.Windows;
9 | using ZuAnBot_Wpf.Constants;
10 |
11 | namespace ZuAnBot_Wpf.Helper
12 | {
13 | ///
14 | /// win32帮助类
15 | ///
16 | public static class Win32Helper
17 | {
18 | public static bool SetWindowForeground(string winTitle)
19 | {
20 | var hWnd = FindWindowEx(IntPtr.Zero, IntPtr.Zero, null, winTitle);
21 |
22 | if (hWnd != IntPtr.Zero)
23 | {
24 | SetForegroundWindow(hWnd); //Activate it
25 | return true;
26 | }
27 |
28 | return false;
29 | }
30 |
31 | public static bool SetMainWindowForeground()
32 | {
33 | return SetWindowForeground(Titles.Main);
34 | }
35 |
36 | public static bool CloseWindow(string winTitle)
37 | {
38 | var hWnd = FindWindowEx(IntPtr.Zero, IntPtr.Zero, null, winTitle);
39 |
40 | if (hWnd != IntPtr.Zero)
41 | {
42 | SendMessage(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0);
43 | return true;
44 | }
45 |
46 | return false;
47 | }
48 |
49 |
50 | [DllImport("user32.dll")]
51 | public static extern IntPtr FindWindowEx(IntPtr handleParent, IntPtr handleChild, string className, string WindowName);
52 |
53 | ///
54 | /// 获取窗体的句柄函数
55 | ///
56 | /// 窗口类名
57 | /// 窗口标题名
58 | /// 返回句柄
59 | [DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
60 | private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
61 |
62 | [DllImport("User32.dll")]
63 | private static extern IntPtr SetForegroundWindow(IntPtr hWnd);
64 |
65 | const int WM_SYSCOMMAND = 0x0112;
66 | const int SC_CLOSE = 0xF060;
67 | [DllImport("user32.dll")]
68 | private static extern int SendMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Helper/WordsHelper.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Linq;
3 | using RestSharp;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using System.Web.UI.WebControls;
10 | using ZuAnBot_Wpf.ViewModels;
11 |
12 | namespace ZuAnBot_Wpf.Helper
13 | {
14 | public class WordsHelper
15 | {
16 |
17 | public static string GetZAWord()
18 | {
19 | var client = new RestClient("https://api.shadiao.app/");
20 | var request = new RestRequest("nmsl", Method.Get);
21 | request.AddParameter("level", "min");
22 | var response = client.Execute(request);
23 | if (response.IsSuccessful)
24 | {
25 | var res = JObject.Parse(response.Content);
26 |
27 | return res["data"]["text"].ToString();
28 | }
29 | else
30 | return "连接服务器失败";
31 | }
32 |
33 |
34 | public static void EnsureValidContent(string value)
35 | {
36 | if( !IsVaileContent(value,out string msg))
37 | {
38 | throw new ArgumentOutOfRangeException(msg, innerException: null);
39 | }
40 | }
41 |
42 | private static bool IsVaileContent(string value,out string msg)
43 | {
44 | if (string.IsNullOrWhiteSpace(value))
45 | {
46 | msg = "词条内容不为空";
47 | return false;
48 | }
49 | if (value.Length > 200)
50 | {
51 | msg = "词条内容不能超过200";
52 | return false;
53 | }
54 |
55 | msg = "";
56 | return true;
57 | }
58 |
59 | public static bool IsVaileContent(string value)
60 | {
61 | return IsVaileContent(value, out _);
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Resources;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using System.Windows;
6 |
7 | // 有关程序集的一般信息由以下
8 | // 控制。更改这些特性值可修改
9 | // 与程序集关联的信息。
10 | [assembly: AssemblyTitle("祖安助手")]
11 | [assembly: AssemblyDescription("")]
12 | [assembly: AssemblyConfiguration("")]
13 | [assembly: AssemblyCompany("")]
14 | [assembly: AssemblyProduct("ZuAnBot_Wpf")]
15 | [assembly: AssemblyCopyright("Copyright © 2022")]
16 | [assembly: AssemblyTrademark("")]
17 | [assembly: AssemblyCulture("")]
18 |
19 | // 将 ComVisible 设置为 false 会使此程序集中的类型
20 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
21 | //请将此类型的 ComVisible 特性设置为 true。
22 | [assembly: ComVisible(false)]
23 |
24 | //若要开始生成可本地化的应用程序,请设置
25 | //.csproj 文件中的 CultureYouAreCodingWith
26 | //例如,如果您在源文件中使用的是美国英语,
27 | //使用的是美国英语,请将 设置为 en-US。 然后取消
28 | //对以下 NeutralResourceLanguage 特性的注释。 更新
29 | //以下行中的“en-US”以匹配项目文件中的 UICulture 设置。
30 |
31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
32 |
33 |
34 | [assembly: ThemeInfo(
35 | ResourceDictionaryLocation.None, //主题特定资源词典所处位置
36 | //(未在页面中找到资源时使用,
37 | //或应用程序资源字典中找到时使用)
38 | ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置
39 | //(未在页面中找到资源时使用,
40 | //、应用程序或任何主题专用资源字典中找到时使用)
41 | )]
42 |
43 |
44 | // 程序集的版本信息由下列四个值组成:
45 | //
46 | // 主版本
47 | // 次版本
48 | // 生成号
49 | // 修订号
50 | //
51 | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
52 | //通过使用 "*",如下所示:
53 | // [assembly: AssemblyVersion("1.0.*")]
54 | [assembly: AssemblyVersion("3.0.2.0")]
55 | [assembly: AssemblyFileVersion("3.0.2.0")]
56 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Properties/app.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
54 |
62 |
63 |
64 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/ViewModels/MainWindowViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Reflection;
7 | using System.Runtime.CompilerServices;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 | using System.Windows;
11 | using System.Windows.Forms;
12 | using Prism.Commands;
13 | using Prism.Mvvm;
14 | using Prism.Services.Dialogs;
15 | using WindowsInput;
16 | using ZuAnBot_Wpf.Api;
17 | using ZuAnBot_Wpf.Constants;
18 | using ZuAnBot_Wpf.Helper;
19 | using ZuAnBot_Wpf.Views;
20 |
21 | namespace ZuAnBot_Wpf.ViewModels
22 | {
23 | public class MainWindowViewModel : BindableBase
24 | {
25 | private readonly IDialogService _dialogService;
26 | private readonly Apis _apis = Apis.GetInstance();
27 | GlobalKeyboardHook hook;
28 |
29 | public WordsLibrary Library { get; set; }
30 |
31 | #region 绑定属性
32 | private bool _IsPerWord = false;
33 | ///
34 | /// 是否逐字发送
35 | ///
36 | public bool IsPerWord
37 | {
38 | get { return _IsPerWord; }
39 | set { SetProperty(ref _IsPerWord, value); }
40 | }
41 |
42 | private bool _IsAll = false;
43 | ///
44 | /// 是否发送所有人消息
45 | ///
46 | public bool IsAll
47 | {
48 | get { return _IsAll; }
49 | set { SetProperty(ref _IsAll, value); }
50 | }
51 |
52 |
53 | private bool _IsNotifyIconBlink;
54 | ///
55 | /// 托盘图标是否闪烁
56 | ///
57 | public bool IsNotifyIconBlink
58 | {
59 | get { return _IsNotifyIconBlink; }
60 | set { SetProperty(ref _IsNotifyIconBlink, value); }
61 | }
62 |
63 | private bool _IsNotifyIconShow = true;
64 | ///
65 | /// 托盘图标是否显示
66 | ///
67 | public bool IsNotifyIconShow
68 | {
69 | get { return _IsNotifyIconShow; }
70 | set { SetProperty(ref _IsNotifyIconShow, value); }
71 | }
72 |
73 | private string _Version;
74 | ///
75 | /// 程序版本号
76 | ///
77 | public string Version
78 | {
79 | get { return _Version; }
80 | set { SetProperty(ref _Version, value); }
81 | }
82 |
83 | private bool _NeedUpdate;
84 | ///
85 | /// 是否需要更新
86 | ///
87 | public bool NeedUpdate
88 | {
89 | get { return _NeedUpdate; }
90 | set { SetProperty(ref _NeedUpdate, value); }
91 | }
92 |
93 | #endregion 绑定属性
94 |
95 | public MainWindowViewModel(IDialogService dialogService)
96 | {
97 | _dialogService = dialogService;
98 | }
99 |
100 | #region 命令
101 | #region LoadedCommand
102 | private DelegateCommand _LoadedCommand;
103 | public DelegateCommand LoadedCommand => _LoadedCommand ?? (_LoadedCommand = new DelegateCommand(ExecuteLoadedCommand));
104 | async void ExecuteLoadedCommand()
105 | {
106 | try
107 | {
108 | LoadWordsLibrary();
109 |
110 | HookKeys();
111 |
112 | Version = "v" + System.Windows.Application.ResourceAssembly.GetName().Version.ToString(3);
113 |
114 | await InitNeedUpdate();
115 | }
116 | catch (Exception e)
117 | {
118 | e.Show();
119 | }
120 | }
121 |
122 | private async Task InitNeedUpdate()
123 | {
124 | var latestVersion = await VersionHelper.GetLatestVersion();
125 | NeedUpdate = !VersionHelper.IsNewestVersion(latestVersion);
126 | }
127 |
128 | private void LoadWordsLibrary()
129 | {
130 | try
131 | {
132 | //第一试用本软件没有本地词库,用资源清单的词库
133 | if (!File.Exists(LocalConfigHelper.WordsLibraryPath))
134 | {
135 | var dir = Path.GetDirectoryName(LocalConfigHelper.WordsLibraryPath);
136 | if (!Directory.Exists(dir))
137 | {
138 | Directory.CreateDirectory(dir);
139 | }
140 |
141 | var manifestStream = ManifestHelper.GetManifestStream("wordsLibrary.json");
142 | using (var stream = File.Create(LocalConfigHelper.WordsLibraryPath))
143 | {
144 | manifestStream.CopyTo(stream);
145 | }
146 | }
147 |
148 | Library = JsonHelper.DeserializeWordsLibrary();//反序列化本地词库
149 | }
150 | catch (Exception e)
151 | {
152 | e.Show("读取词库失败!");
153 | File.Delete(LocalConfigHelper.WordsLibraryPath);
154 | App.Current.Shutdown();
155 | }
156 | }
157 |
158 | #endregion
159 |
160 | #region 访问GitHub
161 | private DelegateCommand _VisitGitHubCommand;
162 | public DelegateCommand VisitGitHubCommand => _VisitGitHubCommand ?? (_VisitGitHubCommand = new DelegateCommand(ExecuteVisitGitHubCommand));
163 | void ExecuteVisitGitHubCommand()
164 | {
165 | try
166 | {
167 | System.Diagnostics.Process.Start("https://github.com/liuke-wuhan/ZuAnBot");
168 | }
169 | catch (Exception e)
170 | {
171 | e.Show();
172 | }
173 | }
174 | #endregion
175 |
176 | #region SetCommand
177 | private DelegateCommand _SetCommand;
178 |
179 | public DelegateCommand SetCommand => _SetCommand ?? (_SetCommand = new DelegateCommand(ExecuteSetCommand));
180 | void ExecuteSetCommand()
181 | {
182 | try
183 | {
184 | var parameters = new DialogParameters();
185 | parameters.Add(Params.Library, Library);
186 | IDialogResult r = null;
187 | _dialogService.ShowDialog(nameof(WordsLibrarySet), parameters, result => r = result);
188 |
189 | if (r.Result == ButtonResult.OK)
190 | {
191 | JsonHelper.SerializeWordsLibrary(Library);
192 | }
193 | else
194 | {
195 | LoadWordsLibrary();
196 | }
197 | }
198 | catch (Exception e)
199 | {
200 | e.Show();
201 | }
202 | }
203 | #endregion
204 |
205 | #region UpdateCommand
206 | private bool _UpdateEnabled = true;
207 | public bool UpdateEnabled
208 | {
209 | get { return _UpdateEnabled; }
210 | set { SetProperty(ref _UpdateEnabled, value); }
211 | }
212 | private DelegateCommand _UpdateCommand;
213 | public DelegateCommand UpdateCommand => _UpdateCommand ?? (_UpdateCommand = new DelegateCommand(ExecuteUpdateCommand).ObservesCanExecute(() => UpdateEnabled));
214 | async void ExecuteUpdateCommand()
215 | {
216 | try
217 | {
218 | UpdateEnabled = false;
219 |
220 | var latestVersion = await VersionHelper.GetLatestVersion();
221 | if (VersionHelper.IsNewestVersion(latestVersion))
222 | {
223 | MessageHelper.Info($"当前版本已经是最新版本");
224 | }
225 | else
226 | {
227 | var result = MessageHelper.Question($"当前版本为{VersionHelper.GetCurrentVersionName()},最新版本为{latestVersion.VersionName},是否更新?");
228 | if (result)
229 | {
230 | var tempDir = Path.GetTempPath();//临时目录
231 | var file = _apis.DownloadFile(tempDir, latestVersion.FileName, latestVersion.Url);//下载到临时目录
232 |
233 | //使用更新
234 | var assembly = Assembly.GetExecutingAssembly();
235 | var stream = assembly.GetManifestResourceStream("costura.zuanbotupdate.exe");
236 | var tempPath = Path.Combine(Path.GetTempPath(), "zuanbotupdate.exe");
237 | using (var tempStream = File.Create(tempPath))
238 | {
239 | stream.CopyTo(tempStream);
240 | }
241 |
242 | var startInfo = new ProcessStartInfo(tempPath, $"\"{file}\" \"{assembly.Location}\"");
243 | //设置不在新窗口中启动新的进程
244 | startInfo.CreateNoWindow = true;
245 | //不使用操作系统使用的shell启动进程
246 | startInfo.UseShellExecute = false;
247 | //将输出信息重定向
248 | startInfo.RedirectStandardOutput = true;
249 | Process.Start(startInfo);
250 | }
251 | }
252 | }
253 | catch (Exception e)
254 | {
255 | e.Show();
256 | }
257 | finally
258 | {
259 | UpdateEnabled = true;
260 | }
261 | }
262 | #endregion
263 |
264 |
265 | #endregion
266 |
267 | ///
268 | /// 按键勾子
269 | ///
270 | private void HookKeys()
271 | {
272 | hook = new GlobalKeyboardHook();
273 | hook.KeyUp += Hook_KeyUp;
274 | hook.HookedKeys.Add(Keys.F2);
275 | hook.HookedKeys.Add(Keys.F3);
276 | hook.HookedKeys.Add(Keys.F11);
277 | hook.HookedKeys.Add(Keys.F12);
278 | hook.hook();
279 | }
280 |
281 | ///
282 | /// 勾子事件处理
283 | ///
284 | ///
285 | ///
286 | private void Hook_KeyUp(object sender, KeyEventArgs e)
287 | {
288 | try
289 | {
290 | string word = "";
291 | if (e.KeyCode == Keys.F2)
292 | word += Library.GetLoacalWord("默认词库");
293 | else if (e.KeyCode == Keys.F3)
294 | word += Library.GetLoacalWord("自定义词库");
295 | else if (e.KeyCode == Keys.F11)
296 | {
297 | IsAll = !IsAll;
298 | return;
299 | }
300 | else if (e.KeyCode == Keys.F12)
301 | {
302 | IsPerWord = !IsPerWord;
303 | return;
304 | }
305 | else
306 | {
307 | return;
308 | }
309 |
310 | string allPre = IsAll ? "/all " : "";
311 |
312 | var builder = Simulate.Events();
313 | if (IsPerWord)
314 | {
315 | foreach (var item in word)
316 | {
317 | builder = builder.
318 | Click(WindowsInput.Events.KeyCode.Enter).Wait(100).
319 | Click(allPre + item).Wait(100).
320 | Click(WindowsInput.Events.KeyCode.Enter).Wait(100);
321 |
322 | }
323 | }
324 | else
325 | {
326 | builder = builder.
327 | Click(WindowsInput.Events.KeyCode.Enter).Wait(100).
328 | Click(allPre + word).Wait(100).
329 | Click(WindowsInput.Events.KeyCode.Enter).Wait(100);
330 | }
331 | builder.Invoke();
332 | }
333 | catch (ArgumentOutOfRangeException)
334 | {
335 | MessageHelper.Error($"词库为空");
336 | }
337 | catch (Exception ex)
338 | {
339 | ex.Show();
340 | }
341 | }
342 |
343 | }
344 | }
345 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/ViewModels/WordEditViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using DryIoc;
7 | using Prism.Commands;
8 | using Prism.Mvvm;
9 | using Prism.Services.Dialogs;
10 | using ZuAnBot_Wpf.Constants;
11 | using ZuAnBot_Wpf.Helper;
12 |
13 | namespace ZuAnBot_Wpf.ViewModels
14 | {
15 | public class WordEditViewModel : BindableBase, IDialogAware
16 | {
17 | private string _Content;
18 | ///
19 | /// 内容
20 | ///
21 | public string Content
22 | {
23 | get { return _Content; }
24 | set
25 | {
26 | SetProperty(ref _Content, value);
27 | }
28 | }
29 |
30 | #region Dialog
31 | public string Title => "词条";
32 |
33 | public event Action RequestClose;
34 |
35 | public bool CanCloseDialog() { return true; }
36 |
37 | public void OnDialogClosed() { }
38 |
39 | public void OnDialogOpened(IDialogParameters parameters)
40 | {
41 | Content = parameters.GetValue(Params.WordContent);
42 | }
43 | #endregion Dialog
44 |
45 | #region OkCommand
46 | private DelegateCommand _OkCommand;
47 | public DelegateCommand OkCommand => _OkCommand ?? (_OkCommand = new DelegateCommand(ExecuteOkCommand));
48 | void ExecuteOkCommand()
49 | {
50 | try
51 | {
52 | WordsHelper.EnsureValidContent(Content);
53 |
54 | var parameters = new DialogParameters();
55 | parameters.Add(Params.WordContent, Content);
56 | RequestClose?.Invoke(new DialogResult(ButtonResult.OK, parameters));
57 | }
58 | catch (ArgumentOutOfRangeException e)
59 | {
60 | e.Show(showDetail: false);
61 | }
62 | catch (Exception e)
63 | {
64 | e.Show();
65 | }
66 | }
67 | #endregion
68 |
69 | #region CancelCommand
70 | private DelegateCommand _CancelCommand;
71 | public DelegateCommand CancelCommand => _CancelCommand ?? (_CancelCommand = new DelegateCommand(ExecuteCancelCommand));
72 | void ExecuteCancelCommand()
73 | {
74 | try
75 | {
76 | RequestClose?.Invoke(new DialogResult(ButtonResult.Cancel));
77 | }
78 | catch (Exception e)
79 | {
80 | e.Show();
81 | }
82 | }
83 | #endregion
84 |
85 |
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/ViewModels/WordLibrary.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Collections.ObjectModel;
4 | using System.Linq;
5 | using System.Windows.Controls;
6 | using Prism.Mvvm;
7 | using Prism.Ioc;
8 | using Prism.Events;
9 | using Prism.Commands;
10 | using ZuAnBot_Wpf.Helper;
11 | using Newtonsoft.Json;
12 | using Prism.Services.Dialogs;
13 | using ZuAnBot_Wpf.Views;
14 | using ZuAnBot_Wpf.Constants;
15 | using ZuAnBot_Wpf.Constants.Events;
16 | using System.Windows;
17 |
18 | namespace ZuAnBot_Wpf.ViewModels
19 | {
20 | ///
21 | /// 词库,包括多类词条
22 | ///
23 | public class WordsLibrary : BindableBase
24 | {
25 | private ObservableCollection _Categories;
26 | public ObservableCollection Categories
27 | {
28 | get { return _Categories; }
29 | set { SetProperty(ref _Categories, value); }
30 | }
31 | }
32 |
33 | ///
34 | /// 词条类
35 | ///
36 | public class WordsCategory : BindableBase
37 | {
38 | [JsonIgnore]
39 | public WordsLibrary Library { get; set; }
40 |
41 | private ObservableCollection _Words;
42 | public ObservableCollection Words
43 | {
44 | get { return _Words; }
45 | set { SetProperty(ref _Words, value); }
46 | }
47 |
48 | private List _TargetCategories;
49 | [JsonIgnore]
50 | ///
51 | /// 其他类别
52 | ///
53 | public List TargetCategories
54 | {
55 | get { return _TargetCategories; }
56 | set { SetProperty(ref _TargetCategories, value); }
57 | }
58 |
59 | public string CategoryName { get; set; }
60 |
61 | private Word _SelectedWord;
62 | [JsonIgnore]
63 | ///
64 | /// 当前选中的word
65 | ///
66 | public Word SelectedWord
67 | {
68 | get { return _SelectedWord; }
69 | set
70 | {
71 | SetProperty(ref _SelectedWord, value);
72 |
73 | DeleteEnabled = value != null;
74 | EditEnabled = value != null;
75 | CopyEnabled = value != null;
76 | }
77 | }
78 |
79 | public WordsCategory()
80 | {
81 | }
82 |
83 | #region 命令
84 |
85 | public void RefreshSelectedWord()
86 | {
87 | SelectedWord = Words.FirstOrDefault(x => x.IsSelected);
88 | }
89 |
90 | #region AddCommand
91 | private bool _AddEnabled = true;
92 | [JsonIgnore]
93 | public bool AddEnabled
94 | {
95 | get { return _AddEnabled; }
96 | set { SetProperty(ref _AddEnabled, value); }
97 | }
98 | private DelegateCommand _AddCommand;
99 | [JsonIgnore]
100 | public DelegateCommand AddCommand => _AddCommand ?? (_AddCommand = new DelegateCommand(ExecuteAddCommand).ObservesCanExecute(() => AddEnabled));
101 | void ExecuteAddCommand()
102 | {
103 | try
104 | {
105 | AddEnabled = false;
106 |
107 | //弹出词条对话框
108 | var dialogService = ContainerLocator.Container.Resolve();
109 |
110 | dialogService.ShowDialog(nameof(WordEdit),
111 | new DialogParameters($"{Params.WordContent}={""}"),
112 | r =>
113 | {
114 | if (r.Result == ButtonResult.OK)
115 | {
116 | var content = r.Parameters.GetValue(Params.WordContent);
117 | var word = new Word { Content = content, Category = this };
118 |
119 | int index;
120 | if (SelectedWord == null)
121 | {
122 | index = 0;
123 | }
124 | else
125 | {
126 | index = Words.IndexOf(SelectedWord) + 1;
127 | }
128 | Words.Insert(index, word);
129 | }
130 | });
131 |
132 | }
133 | catch (ArgumentOutOfRangeException e)
134 | {
135 | e.Show(showDetail: false);
136 | }
137 | catch (Exception e)
138 | {
139 | e.Show();
140 | }
141 | AddEnabled = true;
142 | }
143 | #endregion
144 |
145 | #region DeleteCommand
146 | private bool _DeleteEnabled = false;
147 | [JsonIgnore]
148 | public bool DeleteEnabled
149 | {
150 | get { return _DeleteEnabled; }
151 | set { SetProperty(ref _DeleteEnabled, value); }
152 | }
153 | private DelegateCommand _DeleteCommand;
154 | [JsonIgnore]
155 | public DelegateCommand DeleteCommand => _DeleteCommand ?? (_DeleteCommand = new DelegateCommand(ExecuteDeleteCommand).ObservesCanExecute(() => DeleteEnabled));
156 | void ExecuteDeleteCommand()
157 | {
158 | try
159 | {
160 | DeleteEnabled = false;
161 |
162 | int index = Words.IndexOf(SelectedWord);
163 |
164 | Words.Remove(SelectedWord);
165 |
166 | if (index < Words.Count)
167 | Words[index].IsSelected = true;
168 | }
169 | catch (Exception e)
170 | {
171 | e.Show();
172 | }
173 | DeleteEnabled = true;
174 | }
175 | #endregion
176 |
177 | #region EditCommand
178 | private bool _EditEnabled = false;
179 | [JsonIgnore]
180 | public bool EditEnabled
181 | {
182 | get { return _EditEnabled; }
183 | set { SetProperty(ref _EditEnabled, value); }
184 | }
185 | private DelegateCommand _EditCommand;
186 | [JsonIgnore]
187 | public DelegateCommand EditCommand => _EditCommand ?? (_EditCommand = new DelegateCommand(ExecuteEditCommand).ObservesCanExecute(() => EditEnabled));
188 | void ExecuteEditCommand()
189 | {
190 | try
191 | {
192 | EditEnabled = false;
193 |
194 | //弹出词条对话框
195 | var dialogService = ContainerLocator.Container.Resolve();
196 |
197 | IDialogResult result = null;
198 | dialogService.ShowDialog(nameof(WordEdit),
199 | new DialogParameters($"{Params.WordContent}={SelectedWord.Content}"), r => result = r);
200 |
201 | if (result.Result == ButtonResult.OK)
202 | {
203 | var content = result.Parameters.GetValue(Params.WordContent);
204 |
205 | SelectedWord.Content = content;
206 | }
207 | }
208 | catch (ArgumentOutOfRangeException e)
209 | {
210 | e.Show(showDetail: false);
211 | }
212 | catch (Exception e)
213 | {
214 | e.Show();
215 | }
216 | EditEnabled = true;
217 | }
218 | #endregion
219 |
220 | #region CopyCommand
221 | private bool _CopyEnabled = false;
222 | [JsonIgnore]
223 | public bool CopyEnabled
224 | {
225 | get { return _CopyEnabled; }
226 | set { SetProperty(ref _CopyEnabled, value); }
227 | }
228 | private DelegateCommand _CopyCommand;
229 | [JsonIgnore]
230 | public DelegateCommand CopyCommand => _CopyCommand ?? (_CopyCommand = new DelegateCommand(ExecuteCopyCommand).ObservesCanExecute(() => CopyEnabled));
231 | void ExecuteCopyCommand()
232 | {
233 | try
234 | {
235 | CopyEnabled = false;
236 |
237 | Clipboard.SetText(SelectedWord.Content, TextDataFormat.Text);
238 | }
239 | catch (Exception e)
240 | {
241 | e.Show();
242 | }
243 | CopyEnabled = true;
244 | }
245 | #endregion
246 |
247 | #region CopyToCommand
248 | private DelegateCommand _CopyToCommand;
249 | public DelegateCommand CopyToCommand => _CopyToCommand ?? (_CopyToCommand = new DelegateCommand(ExecuteCopyToCommand));
250 | void ExecuteCopyToCommand(string parameter)
251 | {
252 | try
253 | {
254 | var sourceWord = Library.Categories.SelectMany(x => x.Words).FirstOrDefault(x => x.IsSelected);
255 |
256 | if (sourceWord == null)
257 | {
258 | MessageHelper.Error("未选中任何词条");
259 | return;
260 | }
261 |
262 | var word = new Word() { Content = sourceWord.Content, Category = this };
263 | Words.Insert(0, word);
264 | }
265 | catch (Exception e)
266 | {
267 | e.Show();
268 | }
269 | }
270 | #endregion
271 |
272 | #region PasteCommand
273 | private bool _PasteEnabled = true;
274 | [JsonIgnore]
275 | public bool PasteEnabled
276 | {
277 | get { return _PasteEnabled; }
278 | set { SetProperty(ref _PasteEnabled, value); }
279 | }
280 | private DelegateCommand _PasteCommand;
281 |
282 | [JsonIgnore]
283 | public DelegateCommand PasteCommand => _PasteCommand ?? (_PasteCommand = new DelegateCommand(ExecutePasteCommand).ObservesCanExecute(() => PasteEnabled));
284 | void ExecutePasteCommand()
285 | {
286 | try
287 | {
288 | PasteEnabled = false;
289 |
290 | var clipboardText = Clipboard.GetText(TextDataFormat.Text);
291 |
292 | int offset = 1;
293 | foreach (var text in clipboardText.Split('\n'))
294 | {
295 | if (!WordsHelper.IsVaileContent(text)) continue;
296 |
297 | var word = new Word { Content = text, Category = this };
298 |
299 | int index;
300 | if (SelectedWord == null)
301 | {
302 | index = 0;
303 | }
304 | else
305 | {
306 | index = Words.IndexOf(SelectedWord) + offset++;
307 | }
308 | Words.Insert(index, word);
309 | }
310 | }
311 | catch (ArgumentOutOfRangeException e)
312 | {
313 | e.Show(showDetail: false);
314 | }
315 | catch (Exception e)
316 | {
317 | e.Show();
318 | }
319 | PasteEnabled = true;
320 | }
321 | #endregion
322 |
323 | #endregion 命令
324 |
325 | }
326 |
327 | ///
328 | /// 词条
329 | ///
330 | public class Word : BindableBase
331 | {
332 | [JsonIgnore]
333 | public WordsCategory Category { get; set; }
334 |
335 | private string _Content;
336 | ///
337 | /// 内容
338 | ///
339 | public string Content
340 | {
341 | get { return _Content; }
342 | set
343 | {
344 | value = value.Replace('\r', char.MinValue);
345 |
346 | WordsHelper.EnsureValidContent(value);
347 |
348 | SetProperty(ref _Content, value);
349 | }
350 | }
351 |
352 | private bool _IsSelected;
353 | [JsonIgnore]
354 | ///
355 | /// 是否选中
356 | ///
357 | public bool IsSelected
358 | {
359 | get { return _IsSelected; }
360 | set
361 | {
362 | SetProperty(ref _IsSelected, value);
363 |
364 | Category.RefreshSelectedWord();
365 | }
366 | }
367 | }
368 |
369 | public static class WordsLibraryExtension
370 | {
371 | public static string GetLoacalWord(this WordsLibrary library, string categoryName)
372 | {
373 | var words = library.Categories.First(x => x.CategoryName == categoryName);
374 |
375 | Random random = new Random((int)DateTime.Now.Ticks);
376 | var word = words.Words[random.Next(0, words.Words.Count)];
377 |
378 | return word.Content;
379 | }
380 |
381 | //static int i = 0;
382 | //public static string GetTestWord(out int index)
383 | //{
384 | // index = i;
385 | // if (i >= wordsLibrary.Categories.Count) return "测试完毕!";
386 |
387 | // WordsLibrary words = wordsLibrary;
388 |
389 | // var word = words.Categories[i++];
390 |
391 | // return word;
392 | //}
393 | }
394 | }
395 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/ViewModels/WordsLibrarySetViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Prism.Commands;
7 | using Prism.Mvvm;
8 | using Prism.Services.Dialogs;
9 | using ZuAnBot_Wpf.Constants;
10 | using ZuAnBot_Wpf.Helper;
11 |
12 | namespace ZuAnBot_Wpf.ViewModels
13 | {
14 | ///
15 | /// 词库
16 | ///
17 | /// 后期可考虑分为视图模型和模型
18 | public class WordsLibrarySetViewModel : BindableBase, IDialogAware
19 | {
20 | private WordsLibrary _Library;
21 | ///
22 | /// 词库
23 | ///
24 | public WordsLibrary Library
25 | {
26 | get { return _Library; }
27 | set { SetProperty(ref _Library, value); }
28 | }
29 |
30 | #region IDialogAware
31 | public string Title => "词库定义";
32 |
33 | public event Action RequestClose;
34 |
35 | public bool CanCloseDialog() { return true; }
36 |
37 | public void OnDialogClosed() { }
38 |
39 | public void OnDialogOpened(IDialogParameters parameters)
40 | {
41 | try
42 | {
43 | Library = parameters.GetValue(Params.Library);
44 | }
45 | catch (Exception e)
46 | {
47 | e.Show();
48 | }
49 | }
50 | #endregion IDialogAware
51 |
52 | #region SaveCommand
53 | private DelegateCommand _SaveCommand;
54 | public DelegateCommand SaveCommand => _SaveCommand ?? (_SaveCommand = new DelegateCommand(ExecuteSaveCommand));
55 | void ExecuteSaveCommand()
56 | {
57 | try
58 | {
59 | RequestClose?.Invoke(new DialogResult(ButtonResult.OK));
60 | }
61 | catch (Exception e)
62 | {
63 | e.Show();
64 | }
65 | }
66 | #endregion
67 |
68 | #region CancelCommand
69 | private DelegateCommand _CancelCommand;
70 | public DelegateCommand CancelCommand => _CancelCommand ?? (_CancelCommand = new DelegateCommand(ExecuteCancelCommand));
71 | void ExecuteCancelCommand()
72 | {
73 | try
74 | {
75 | RequestClose?.Invoke(new DialogResult(ButtonResult.Cancel));
76 | }
77 | catch (Exception e)
78 | {
79 | e.Show();
80 | }
81 | }
82 | #endregion
83 |
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Views/Conveters/Bool2Brush.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Globalization;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using System.Windows.Data;
8 | using System.Windows.Media;
9 |
10 | namespace ZuAnBot_Wpf.Views.Conveters
11 | {
12 | public class Bool2Brush : IValueConverter
13 | {
14 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
15 | {
16 | var b = (bool)value;
17 |
18 | if (b)
19 | return new SolidColorBrush(Colors.Red);
20 | else
21 | return new SolidColorBrush(Colors.Black);
22 | }
23 |
24 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
25 | {
26 | throw new NotImplementedException();
27 | }
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Views/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
34 |
35 |
39 |
49 |
50 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
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 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Views/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Runtime.InteropServices;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using System.Windows;
9 | using System.Windows.Controls;
10 | using System.Windows.Data;
11 | using System.Windows.Documents;
12 | using System.Windows.Input;
13 | using System.Windows.Interop;
14 | using System.Windows.Media;
15 | using System.Windows.Media.Imaging;
16 | using System.Windows.Navigation;
17 | using System.Windows.Shapes;
18 | using DryIoc.Messages;
19 | using ZuAnBot_Wpf.Helper;
20 |
21 | namespace ZuAnBot_Wpf.Views
22 | {
23 | ///
24 | /// MainWindow.xaml 的交互逻辑
25 | ///
26 | public partial class MainWindow
27 | {
28 | public MainWindow()
29 | {
30 | InitializeComponent();
31 |
32 | checkBox_isPerword_notifyIcon.SetBinding(CheckBox.IsCheckedProperty, new Binding("IsChecked") { Source = checkBox_isPerword });
33 | checkBox_isAll_notifyIcon.SetBinding(CheckBox.IsCheckedProperty, new Binding("IsChecked") { Source = checkBox_isAll });
34 | }
35 |
36 | ///
37 | /// IPC
38 | ///
39 | ///
40 | protected override void OnSourceInitialized(EventArgs e)
41 | {
42 | base.OnSourceInitialized(e);
43 |
44 | IPCHelper.ObserveMessage(this, msg =>
45 | {
46 | if (msg == "显示")
47 | {
48 | Button_Click(this, null);
49 | }
50 | });
51 | }
52 |
53 | ///
54 | /// 拦截最小化
55 | ///
56 | ///
57 | ///
58 | private void Window_StateChanged(object sender, EventArgs e)
59 | {
60 | if (WindowState == WindowState.Minimized)
61 | {
62 | WindowState = WindowState.Normal;
63 | Hide();
64 | }
65 | }
66 |
67 | ///
68 | /// 显示主界面
69 | ///
70 | ///
71 | ///
72 | private void Button_Click(object sender, RoutedEventArgs e)
73 | {
74 | Show();
75 | Win32Helper.SetMainWindowForeground();
76 | }
77 |
78 | ///
79 | /// 退出
80 | ///
81 | ///
82 | ///
83 | private void Button_Quit_Click(object sender, RoutedEventArgs e)
84 | {
85 | System.Windows.Application.Current.Shutdown();
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Views/WordEdit.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Views/WordEdit.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Navigation;
14 | using System.Windows.Shapes;
15 |
16 | namespace ZuAnBot_Wpf.Views
17 | {
18 | ///
19 | /// WordEdit.xaml 的交互逻辑
20 | ///
21 | public partial class WordEdit : UserControl
22 | {
23 | public WordEdit()
24 | {
25 | InitializeComponent();
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Views/WordsLibrarySet.xaml:
--------------------------------------------------------------------------------
1 |
13 |
14 |
19 |
20 |
21 |
22 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
58 |
61 |
64 |
67 |
68 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
86 |
87 |
88 |
89 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/Views/WordsLibrarySet.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Navigation;
14 | using System.Windows.Shapes;
15 |
16 | namespace ZuAnBot_Wpf.Views
17 | {
18 | ///
19 | /// WordsLibrarySet.xaml 的交互逻辑
20 | ///
21 | public partial class WordsLibrarySet : UserControl
22 | {
23 | public WordsLibrarySet()
24 | {
25 | InitializeComponent();
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/ZuAnBot_Wpf.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net472
4 | WinExe
5 | false
6 | true
7 | true
8 | ZuAnBot_Wpf.App
9 | x86
10 | Assets\Images\祖安.ico
11 | 祖安助手
12 | Properties\app.manifest
13 |
14 |
15 | embedded
16 |
17 |
18 | embedded
19 |
20 |
21 |
22 |
26 |
27 |
28 |
29 |
30 |
31 | all
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
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 |
--------------------------------------------------------------------------------
/ZuAnBot_Wpf/build.bat:
--------------------------------------------------------------------------------
1 | ::ZuAnBot_Wpf安装nuget包:Costura.Fody
2 | dotnet add package Costura.Fody
3 |
4 | ::ZuAnBotUpdate安装nuget包:Costura.Fody
5 | cd ..
6 | cd ZuAnBotUpdate
7 | dotnet add package Costura.Fody
8 |
9 | ::release模式生成exe
10 | cd ..
11 | cd ZuAnBot_Wpf
12 | dotnet build --configuration Release
13 |
14 | ::ZuAnBotUpdate卸载nuget包:Costura.Fody
15 | cd ..
16 | cd ZuAnBotUpdate
17 | dotnet remove package Costura.Fody
18 |
19 | ::ZuAnBot_Wpf安装nuget包:Costura.Fody
20 | cd ..
21 | cd ZuAnBot_Wpf
22 | dotnet remove package Costura.Fody
23 |
24 | pause
--------------------------------------------------------------------------------
/截图_客户端.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liuke-wuhan/ZuAnBot/31e695a5c80efa53f354624c2ed530a26c36b96f/截图_客户端.png
--------------------------------------------------------------------------------
/截图_游戏.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liuke-wuhan/ZuAnBot/31e695a5c80efa53f354624c2ed530a26c36b96f/截图_游戏.jpg
--------------------------------------------------------------------------------
/截图_自定义词库.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liuke-wuhan/ZuAnBot/31e695a5c80efa53f354624c2ed530a26c36b96f/截图_自定义词库.png
--------------------------------------------------------------------------------
/截图_软件.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/liuke-wuhan/ZuAnBot/31e695a5c80efa53f354624c2ed530a26c36b96f/截图_软件.png
--------------------------------------------------------------------------------