@@ -13,6 +13,10 @@ internal class Program
13
13
public static bool force = false ;
14
14
public static ProgressBar ? progress = null ;
15
15
16
+
17
+ /*
18
+ * Helptext option definitions
19
+ */
16
20
private static readonly List < string > preOptions =
17
21
new List < string > ( ) {
18
22
"\n \n USAGE:" ,
@@ -29,21 +33,23 @@ internal class Program
29
33
" 127 - Bad Request"
30
34
} ;
31
35
36
+
32
37
public static int Main ( string [ ] args )
33
38
{
34
39
ParserResult < Options > parser = new Parser ( with => {
35
40
with . HelpWriter = null ;
36
41
with . CaseInsensitiveEnumValues = true ;
37
42
} ) . ParseArguments < Options > ( args ) ;
38
43
44
+ // argument parser success
39
45
parser . WithParsed ( options =>
40
46
{
41
47
logLevel = options . LogLevel ;
42
48
force = options . Force ;
43
49
LogService . OnLog += OnLog ;
44
50
CompareService . OnProgress += OnProgress ;
45
51
46
- // custom validation
52
+ // custom validation of argument dependecies not covered by library
47
53
List < string > customErrors = new ( ) ;
48
54
49
55
if ( options . Processors . Count ( ) == 0 && ( options . Action == Models . Action . Move || options . Action == Models . Action . Bin || options . Action == Models . Action . Delete ) )
@@ -61,6 +67,7 @@ public static int Main(string[] args)
61
67
if ( options . Cache . Length == 0 && options . Action == Models . Action . NoMatch )
62
68
customErrors . Add ( $ "Required option 'c, cache' missing on action '{ options . Action } '") ;
63
69
70
+ // console output for custom errors
64
71
if ( customErrors . Count > 0 )
65
72
{
66
73
ParserResult < Options > errorParser = new Parser ( with =>
@@ -87,6 +94,7 @@ public static int Main(string[] args)
87
94
. AddPostOptionsLines ( postOptions )
88
95
) ;
89
96
} ) ;
97
+
90
98
return ;
91
99
}
92
100
@@ -95,22 +103,27 @@ public static int Main(string[] args)
95
103
string hashVersion = HashService . GetIdentifier ( options . HashDetail , options . HashAlgorithm ) ;
96
104
ulong scantime = ( ulong ) ( DateTime . Now - new DateTime ( 1970 , 1 , 1 , 0 , 0 , 0 , 0 ) ) . TotalSeconds ;
97
105
106
+ // scan directories for files
98
107
options . Locations = options . Locations . Select ( l => Path . IsPathRooted ( l ) ? l : Path . Combine ( Assembly . GetExecutingAssembly ( ) . Location , l ) ) ;
99
108
List < List < FileInfo > > searchLocations = FileService . SearchProcessableFiles ( options . Locations . ToArray ( ) , options . Recursive ) ;
100
109
110
+ // get already analysed images from cache (if specified)
101
111
FileService . DataDirectory = Path . IsPathRooted ( options . Cache ) ? ( Path . GetDirectoryName ( options . Cache ) ?? FileService . DataDirectory ) : Path . Combine ( Assembly . GetExecutingAssembly ( ) . Location , Path . GetDirectoryName ( options . Cache ) ?? ".\\ " ) ;
102
112
FileService . CacheFile = Path . GetFileName ( options . Cache ) . NullIfEmpty ( ) ?? FileService . CacheFile ;
103
113
if ( options . Cache . Length >= 1 )
104
114
CacheService . Init ( ) ;
105
115
List < CacheItem > cachedAnalysis = options . Cache . Length >= 1 ? CacheService . GetImages ( hashVersion ) : new ( ) ;
106
116
117
+ // analyse all new or modified images
107
118
List < List < ImageAnalysis > > analysedImages = CompareService . AnalyseImages ( searchLocations , options . HashDetail , options . HashAlgorithm , cachedAnalysis ) ;
108
119
if ( options . Cache . Length >= 1 )
109
120
CacheService . UpdateImages ( analysedImages . SelectMany ( i => i ) . ToList ( ) , hashVersion , scantime ) ;
110
121
122
+ // sort out all duplicates or nomatches
111
123
List < NoMatch > nomatches = options . Cache . Length >= 1 ? CacheService . GetNoMatches ( ) : new ( ) ;
112
124
List < ImageMatch > Matches = CompareService . SearchForDuplicates ( analysedImages , options . Similarity , options . SearchMode , nomatches ) ;
113
125
126
+ // output csv Search results
114
127
if ( options . Action == Models . Action . Search )
115
128
{
116
129
if ( logLevel < LogLevel . Warning )
@@ -119,24 +132,28 @@ public static int Main(string[] args)
119
132
{
120
133
Console . WriteLine ( $ "\" { m . Image1 . Image . FullName } \" ,\" { m . Image2 . Image . FullName } \" ,{ m . Similarity } ") ;
121
134
} ) ;
135
+
122
136
return ;
123
137
}
124
138
139
+ // fill cache with found matches
125
140
if ( options . Action == Models . Action . NoMatch )
126
141
{
127
142
LogService . Log ( "Filling no-match cache with current results due to user request" , LogLevel . Warning ) ;
128
143
CacheService . AddNoMatches ( Matches ) ;
144
+
129
145
return ;
130
146
}
131
147
132
- // just to be sure that files dont get processed on an unexpected action input
148
+ // check action again just to be sure that files dont get processed on an unexpected action input
133
149
if ( options . Action == Models . Action . Move || options . Action == Models . Action . Bin || options . Action == Models . Action . Delete ) {
134
150
DeleteAction deleteAction ;
135
151
136
152
switch ( options . Action )
137
153
{
138
154
case Models . Action . Move :
139
155
deleteAction = DeleteAction . Move ;
156
+ // trailing slash because target path needs to be directory
140
157
if ( ! options . Target . EndsWith ( "\\ " ) && ! options . Target . EndsWith ( "/" ) )
141
158
options . Target += "\\ " ;
142
159
break ;
@@ -151,11 +168,13 @@ public static int Main(string[] args)
151
168
List < string > processedFiles = new ( ) ;
152
169
Matches . ForEach ( m =>
153
170
{
171
+ // don't delete files if the match or the file itself already has been deleted
154
172
if ( processedFiles . Any ( p => p == m . Image1 . Image . FullName || p == m . Image2 . Image . FullName ) )
155
173
return ;
156
174
157
175
for ( int i = 0 ; i < options . Processors . Count ( ) ; i ++ )
158
176
{
177
+ // check first distinguishable property in given processors and take action if possible
159
178
int processingResult = AutoProcessorService . Processors . First ( p => p . DisplayName == options . Processors . ElementAt ( i ) ) . Process ( m . Image1 . Image , m . Image2 . Image ) ;
160
179
if ( processingResult != 0 )
161
180
{
@@ -182,6 +201,8 @@ public static int Main(string[] args)
182
201
{
183
202
LogService . Log ( $ "Error Auto-Processing current match: '{ m . Image1 . Image . FullName } ' - '{ m . Image2 . Image . FullName } '", LogLevel . Error ) ;
184
203
}
204
+
205
+ break ;
185
206
}
186
207
}
187
208
} ) ;
@@ -194,6 +215,7 @@ public static int Main(string[] args)
194
215
}
195
216
196
217
} )
218
+ // console argument parser failure (or help requested)
197
219
. WithNotParsed ( errors =>
198
220
{
199
221
Console . WriteLine (
@@ -215,7 +237,11 @@ public static int Main(string[] args)
215
237
return ( int ) exit ;
216
238
}
217
239
218
- public static void OnProgress ( object ? sender , ImageComparerEventArgs e )
240
+
241
+ /*
242
+ * Progress ticker for image analysation progress bar
243
+ */
244
+ private static void OnProgress ( object ? sender , ImageComparerEventArgs e )
219
245
{
220
246
if ( e . Target > 0 )
221
247
{
@@ -230,6 +256,7 @@ public static void OnProgress(object? sender, ImageComparerEventArgs e)
230
256
}
231
257
}
232
258
259
+
233
260
/*
234
261
* Log implementation for console output
235
262
*/
0 commit comments