-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathProgram.vb
392 lines (318 loc) · 14.8 KB
/
Program.vb
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
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
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
Imports System.IO
Imports System.Text
Imports System.Threading
Imports System.Windows.Forms
Imports Newtonsoft.Json
Imports SixLabors.ImageSharp
Module Program
Sub Main(args As String()) 'Entry point
MainAsync(args).GetAwaiter().GetResult()
End Sub
Private Async Function MainAsync(args As String()) As Task
' Handle context menu calls
Await CatchContextMenuCallAsync(args)
' Don't allow concurrent instances of the app
ExitIfAppIsAlreadyRunning()
' Set global loglevel, parse from arguments
SetLogLevel(args)
' Hook exit event, saves current config and disposes logger
AddHandler AppDomain.CurrentDomain.ProcessExit, AddressOf ProcessExit
' First call of Log() initializes the logger
Log(LogLvl.Info, "Jiraisho v0.1")
Log(LogLvl.Debug, $"IsHardwareAccelerated = {Numerics.Vector.IsHardwareAccelerated}")
' Register/Update app path to enable direct calls via jiraisho.exe
Registry.UpdateAppPath()
' Load Config from json
LoadConfig()
' Create directorys set in config
CreateDirectorys()
' Init downloader, manages downloads of new wallpapers
Downloader = New DownloadClient
' Check internet connection
Await CheckInternetConnectionAsync()
' Init source
Await Downloader.SetCurrentSourceAsync(CFG.Source, CFG.Username, CFG.Password)
' Init desktop, manages monitors, desktops and wallpapers
Desktop = New DesktopClient
' Image manipuation setting
InitImageSharp()
' Handles the actual work, downloads new image, sets it as background
StartProcessingLoop()
' Start user interface (tray icon, hotkeys, settings)
StartUI() ' Blocks until UI closes
End Function
Private Async Function CatchContextMenuCallAsync(args As String()) As Task
If args IsNot Nothing AndAlso args.Length > 0 AndAlso args(0).Contains("cmt") Then
'App was called from context menu
Try
'Can't access the same logfile from two applications
Logger.DisableFilelogger()
'Get selected screen
Dim selectedScreen = Screen.FromPoint(Cursor.Position)
Select Case args(1)
Case "fav"
Await UserActions.FavWallpaper(selectedScreen)
Case "save"
UserActions.SaveWallpaper(selectedScreen)
Case "open"
UserActions.OpenWallpaper(selectedScreen)
Case "favlast"
Await UserActions.FavWallpaper(selectedScreen, last:=True)
Case "savelast"
UserActions.SaveWallpaper(selectedScreen, last:=True)
Case "openlast"
UserActions.OpenWallpaper(selectedScreen, last:=True)
Case Else
Log(LogLvl.Error, "Can't process " & args(1))
End Select
Catch ex As Exception
MessageBox.Show(ex.ToString(), AppName & " - Error")
Finally
'Always exit on context menu calls
Environment.Exit(0)
End Try
End If
End Function
Private Sub ExitIfAppIsAlreadyRunning()
If System.Diagnostics.Process.GetProcessesByName(System.IO.Path.GetFileNameWithoutExtension(System.Reflection.Assembly.GetEntryAssembly().Location)).Count() > 1 Then
MessageBox.Show("App is already running!", AppName)
Environment.Exit(0)
End If
End Sub
Private Sub SetLogLevel(args As String())
#If DEBUG Then
'Always log everything while debugging
GlobalLogLevel = LogLvl.Trace
#Else
If args IsNot Nothing AndAlso args.Length > 0 Then
'First arg = loglevel, enables logging
If Not String.IsNullOrWhiteSpace(args(0)) Then
Select Case args(0).Trim().ToLowerInvariant()
Case "0", "trace"
GlobalLogLevel = LogLvl.Trace
Case "1", "debug"
GlobalLogLevel = LogLvl.Debug
Case "2", "info", "information", "enabled", "log", "true"
GlobalLogLevel = LogLvl.Info
Case "3", "warning"
GlobalLogLevel = LogLvl.Warning
Case "4", "error"
GlobalLogLevel = LogLvl.Error
Case "5", "critical"
GlobalLogLevel = LogLvl.Critical
Case Else
'Will also disable all message boxes
GlobalLogLevel = 6
FileLogDisabled = True
End Select
End If
Else
'Disable file-logging by default
GlobalLogLevel = LogLvl.Error
FileLogDisabled = True
End If
#End If
End Sub
Private Sub ProcessExit(sender As Object, e As EventArgs)
Try
Dim json = JsonConvert.SerializeObject(CFG, Formatting.Indented)
Dim fi = New System.IO.FileInfo(PATH_CONFIG)
fi.Directory.Create()
File.WriteAllText(PATH_CONFIG, json, New UTF8Encoding(False))
Catch ex As Exception
Log(LogLvl.Warning, "Could not save config", ex)
End Try
DisposeLogger()
End Sub
#Region "Config"
Public CFG As Config
Public DIR_CONFIG As String = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), AppName)
Private PATH_CONFIG As String = Path.Combine(DIR_CONFIG, ".\config.json")
Private Sub LoadConfig()
Log(LogLvl.Trace, "Called")
Dim defaultConfig = New Config With {
.Source = "Konachan",
.Rating = Rating.Safe,
.IntervalInSeconds = 30,
.SkipObscuredMonitors = True,
.PauseIfIdling = True,
.DirHistory = Path.Combine(Path.GetTempPath(), AppName, "History"),
.DirSaved = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), AppName),
.MaxHistory = 10,
.HK_SaveCurrent = (HK_Modifier.MOD_ALT, Keys.S),
.HK_OpenCurrent = (HK_Modifier.MOD_ALT, Keys.O),
.HK_FavCurrent = (HK_Modifier.MOD_ALT, Keys.F),
.ContextMenu = ContextMenuType.Grouped,
.ContextMenuFav = True,
.ContextMenuDislike = True,
.ContextMenuSave = True,
.ContextMenuOpen = True,
.ContextMenuFavLast = True,
.ContextMenuDislikeLast = True,
.ContextMenuSaveLast = True,
.ContextMenuOpenLast = True,
.SettingsWindowDefaultPosition = New Drawing.Point(256, 256) 'ToDo: Store this in registry
}
If Not File.Exists(PATH_CONFIG) Then
CFG = defaultConfig
Dim json = JsonConvert.SerializeObject(CFG, Formatting.Indented)
Try
Dim fi = New System.IO.FileInfo(PATH_CONFIG)
fi.Directory.Create()
File.WriteAllText(PATH_CONFIG, json, New UTF8Encoding(False))
Catch ex As Exception
Log(LogLvl.Warning, "Can't write config file", ex)
End Try
Else
Try
Dim json = File.ReadAllText(PATH_CONFIG, New UTF8Encoding(False))
CFG = JsonConvert.DeserializeObject(Of Config)(json)
Catch ex As Exception
CFG = defaultConfig
Dim json = JsonConvert.SerializeObject(CFG, Formatting.Indented)
Dim fi = New System.IO.FileInfo(PATH_CONFIG)
fi.Directory.Create()
File.WriteAllText(PATH_CONFIG, json, New UTF8Encoding(False))
Log(LogLvl.Error, "Can't load config. Config file reset to defaults.", ex)
End Try
End If
'Check values
If Not DownloadClient.Sources.Contains(CFG.Source) Then
CFG.Source = defaultConfig.Source
End If
If CFG.Rating < 0 OrElse CFG.Rating > Rating.All Then
CFG.Rating = defaultConfig.Rating
End If
If CFG.MinResolution < 0! OrElse CFG.MinResolution > 1.0! Then
CFG.MinResolution = defaultConfig.MinResolution
End If
If CFG.IntervalInSeconds < 5 Then
CFG.IntervalInSeconds = 5
End If
If String.IsNullOrWhiteSpace(CFG.DirHistory) Then
CFG.DirHistory = defaultConfig.DirHistory
End If
If String.IsNullOrWhiteSpace(CFG.DirSaved) Then
CFG.DirSaved = defaultConfig.DirSaved
End If
'Max history get's checked in the DesktopClient constructor
Dim modi = CFG.HK_SaveCurrent.Item1
Dim key = CFG.HK_SaveCurrent.Item2
If modi < HK_Modifier.MOD_ALT OrElse modi > HK_Modifier.MOD_CONTROL_SHIFT OrElse modi = HK_Modifier.MOD_WIN OrElse modi = HK_Modifier.MOD_NOREPEAT Then
CFG.HK_SaveCurrent = defaultConfig.HK_SaveCurrent
End If
modi = CFG.HK_OpenCurrent.Item1
key = CFG.HK_OpenCurrent.Item2
If modi < HK_Modifier.MOD_ALT OrElse modi > HK_Modifier.MOD_CONTROL_SHIFT OrElse modi = HK_Modifier.MOD_WIN OrElse modi = HK_Modifier.MOD_NOREPEAT Then
CFG.HK_OpenCurrent = defaultConfig.HK_OpenCurrent
End If
If CFG.ContextMenu < ContextMenuType.None OrElse CFG.ContextMenu > ContextMenuType.CascadedGrouped Then
CFG.ContextMenu = defaultConfig.ContextMenu
End If
If CFG.SettingsWindowDefaultPosition.X < 0 OrElse CFG.SettingsWindowDefaultPosition.Y < 0 Then
CFG.SettingsWindowDefaultPosition = defaultConfig.SettingsWindowDefaultPosition
End If
'Update registry
Registry.SetValue("DirSaved", CFG.DirSaved)
Registry.DeleteContextMenu()
If CFG.ContextMenu <> ContextMenuType.None Then
Registry.CreateContextMenu(CFG.ContextMenu, CFG.ContextMenuFav, CFG.ContextMenuDislike, CFG.ContextMenuSave, CFG.ContextMenuOpen, CFG.ContextMenuFavLast, CFG.ContextMenuDislikeLast, CFG.ContextMenuSaveLast, CFG.ContextMenuOpenLast)
End If
Log(LogLvl.Trace, "Reached end")
End Sub
#End Region
Private Sub CreateDirectorys()
Log(LogLvl.Trace, "Called")
Try
IO.Directory.CreateDirectory(CFG.DirHistory)
Catch ex As Exception
Log(LogLvl.Critical, "Can't create history directory.", ex)
End Try
Try
IO.Directory.CreateDirectory(CFG.DirSaved)
Catch ex As Exception
Log(LogLvl.Critical, "Can't create saved directory.", ex)
End Try
Log(LogLvl.Trace, "Reached end")
End Sub
Private Async Function CheckInternetConnectionAsync() As Task
Log(LogLvl.Trace, "Called")
Dim failCount As Integer = 0
Do While Not Await Downloader.CheckInternetConnectionAsync()
failCount += 1
If failCount > 3 Then
Log(LogLvl.Critical, $"Can't reach the internet.{vbCrLf}Can't download wallpapers without access to the internet.")
End If
Await Task.Delay(4000)
Loop
Log(LogLvl.Trace, "Reached end")
End Function
Private Sub InitImageSharp()
'ToDo: Configurable?
Configuration.Default.MaxDegreeOfParallelism = Environment.ProcessorCount / 2
'ToDo: Performance testing: memory vs cpu, -> Make configurable
Configuration.Default.MemoryAllocator = SixLabors.ImageSharp.Memory.ArrayPoolMemoryAllocator.CreateWithModeratePooling()
End Sub
Private Sub StartProcessingLoop()
Log(LogLvl.Trace, "Called")
'Ensure that there is a wallpaper for every monitor already
GetNextWallpaperForAllMonitors()
SlideshowTimer = New Timers.Timer
AddHandler SlideshowTimer.Elapsed, AddressOf ProcessingLoop.ProcessingLoop
SlideshowTimer.Interval = 3000 'Set interval gets set after first wallpaper change
SlideshowTimer.AutoReset = True
SlideshowTimer.Start()
Log(LogLvl.Debug, $"Diashow timer started")
End Sub
Sub StartUI()
Log(LogLvl.Trace, "Called")
'Run UI on a seperate thread, because it needs a STAThread
Dim UIThread = New Thread(Sub() Application.Run(New UserInterface))
UIThread.SetApartmentState(ApartmentState.STA)
UIThread.Start()
UIThread.Join() 'Blocks until Application closes
End Sub
Public Class Config
'General
<JsonProperty(Order:=0)> Public StartWithWindows As Boolean
<JsonProperty(Order:=1)> Public CheckForUpdates As Boolean
'Source
<JsonProperty(Order:=2)> Public Source As String
<JsonProperty(Order:=3)> Public Username As String
<JsonProperty(Order:=4)> Friend Password As String 'ToDo: Encrypt?
'Search
<JsonProperty(Order:=5)> Public Rating As Rating
<JsonProperty(Order:=6)> Public CustomTags As String()
<JsonProperty(Order:=7)> Public OnlyDesktopRatio As Boolean
<JsonProperty(Order:=8)> Public AllowSmallDeviations As Boolean
<JsonProperty(Order:=9)> Public MinResolution As Single
'Wallpaper
<JsonProperty(Order:=10)> Public IntervalInSeconds As Integer
<JsonProperty(Order:=11)> Public Style As SortedList(Of Integer, CustomStyle)
<JsonProperty(Order:=12)> Public SkipObscuredMonitors As Boolean
<JsonProperty(Order:=13)> Public PauseIfIdling As Boolean
'Files
<JsonProperty(Order:=14)> Public DirHistory As String
<JsonProperty(Order:=15)> Public DirSaved As String
<JsonProperty(Order:=16)> Public MaxHistory As Integer
'Hotkeys
<JsonProperty(Order:=17)> Public HK_SaveCurrent As (HK_Modifier, Keys)
<JsonProperty(Order:=18)> Public HK_OpenCurrent As (HK_Modifier, Keys)
<JsonProperty(Order:=19)> Public HK_FavCurrent As (HK_Modifier, Keys)
'ContextMenu
<JsonProperty(Order:=20)> Public ContextMenu As ContextMenuType
<JsonProperty(Order:=21)> Public ContextMenuFav As Boolean
<JsonProperty(Order:=22)> Public ContextMenuDislike As Boolean
<JsonProperty(Order:=23)> Public ContextMenuSave As Boolean
<JsonProperty(Order:=24)> Public ContextMenuOpen As Boolean
<JsonProperty(Order:=25)> Public ContextMenuFavLast As Boolean
<JsonProperty(Order:=26)> Public ContextMenuDislikeLast As Boolean
<JsonProperty(Order:=27)> Public ContextMenuSaveLast As Boolean
<JsonProperty(Order:=28)> Public ContextMenuOpenLast As Boolean
'Misc
<JsonProperty(Order:=29)> Public SettingsWindowDefaultPosition As Drawing.Point 'ToDo: Save this in registry?
Public Function Clone() As Config
Return Me.MemberwiseClone()
End Function
End Class
End Module