Skip to content

Commit 0df5d0d

Browse files
author
DerEffi
committed
added docs
1 parent cf3870c commit 0df5d0d

19 files changed

+326
-25
lines changed

ImageComparison/Models/Action.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66

77
namespace ImageComparison.Models
88
{
9+
/// <summary>
10+
/// Console Action for found matches
11+
/// </summary>
912
public enum Action
1013
{
1114
Search,

ImageComparison/Models/CacheItem.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66

77
namespace ImageComparison.Models
88
{
9+
/// <summary>
10+
/// Data Structure for stored analysis items in database
11+
/// </summary>
912
public class CacheItem
1013
{
1114
public string path;

ImageComparison/Models/ImageAnalysis.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ public class ImageAnalysis
55
public FileInfo Image { get; set; }
66
public ulong[] Hash { get; set; }
77

8+
/// <summary>
9+
/// Blob converted hash value for disk/database/cache storage
10+
/// </summary>
811
public byte[] HashBlob {
912
get {
1013
byte[] blob = new byte[Hash.Length * 8];

ImageComparison/Program.cs

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ internal class Program
1313
public static bool force = false;
1414
public static ProgressBar? progress = null;
1515

16+
17+
/*
18+
* Helptext option definitions
19+
*/
1620
private static readonly List<string> preOptions =
1721
new List<string>(){
1822
"\n\nUSAGE:",
@@ -29,21 +33,23 @@ internal class Program
2933
" 127 - Bad Request"
3034
};
3135

36+
3237
public static int Main(string[] args)
3338
{
3439
ParserResult<Options> parser = new Parser(with => {
3540
with.HelpWriter = null;
3641
with.CaseInsensitiveEnumValues = true;
3742
}).ParseArguments<Options>(args);
3843

44+
// argument parser success
3945
parser.WithParsed(options =>
4046
{
4147
logLevel = options.LogLevel;
4248
force = options.Force;
4349
LogService.OnLog += OnLog;
4450
CompareService.OnProgress += OnProgress;
4551

46-
// custom validation
52+
// custom validation of argument dependecies not covered by library
4753
List<string> customErrors = new();
4854

4955
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)
6167
if (options.Cache.Length == 0 && options.Action == Models.Action.NoMatch)
6268
customErrors.Add($"Required option 'c, cache' missing on action '{options.Action}'");
6369

70+
// console output for custom errors
6471
if (customErrors.Count > 0)
6572
{
6673
ParserResult<Options> errorParser = new Parser(with =>
@@ -87,6 +94,7 @@ public static int Main(string[] args)
8794
.AddPostOptionsLines(postOptions)
8895
);
8996
});
97+
9098
return;
9199
}
92100

@@ -95,22 +103,27 @@ public static int Main(string[] args)
95103
string hashVersion = HashService.GetIdentifier(options.HashDetail, options.HashAlgorithm);
96104
ulong scantime = (ulong)(DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalSeconds;
97105

106+
// scan directories for files
98107
options.Locations = options.Locations.Select(l => Path.IsPathRooted(l) ? l : Path.Combine(Assembly.GetExecutingAssembly().Location, l));
99108
List<List<FileInfo>> searchLocations = FileService.SearchProcessableFiles(options.Locations.ToArray(), options.Recursive);
100109

110+
// get already analysed images from cache (if specified)
101111
FileService.DataDirectory = Path.IsPathRooted(options.Cache) ? (Path.GetDirectoryName(options.Cache) ?? FileService.DataDirectory) : Path.Combine(Assembly.GetExecutingAssembly().Location, Path.GetDirectoryName(options.Cache) ?? ".\\");
102112
FileService.CacheFile = Path.GetFileName(options.Cache).NullIfEmpty() ?? FileService.CacheFile;
103113
if (options.Cache.Length >= 1)
104114
CacheService.Init();
105115
List<CacheItem> cachedAnalysis = options.Cache.Length >= 1 ? CacheService.GetImages(hashVersion) : new();
106116

117+
// analyse all new or modified images
107118
List<List<ImageAnalysis>> analysedImages = CompareService.AnalyseImages(searchLocations, options.HashDetail, options.HashAlgorithm, cachedAnalysis);
108119
if (options.Cache.Length >= 1)
109120
CacheService.UpdateImages(analysedImages.SelectMany(i => i).ToList(), hashVersion, scantime);
110121

122+
// sort out all duplicates or nomatches
111123
List<NoMatch> nomatches = options.Cache.Length >= 1 ? CacheService.GetNoMatches() : new();
112124
List<ImageMatch> Matches = CompareService.SearchForDuplicates(analysedImages, options.Similarity, options.SearchMode, nomatches);
113125

126+
// output csv Search results
114127
if (options.Action == Models.Action.Search)
115128
{
116129
if (logLevel < LogLevel.Warning)
@@ -119,24 +132,28 @@ public static int Main(string[] args)
119132
{
120133
Console.WriteLine($"\"{m.Image1.Image.FullName}\",\"{m.Image2.Image.FullName}\",{m.Similarity}");
121134
});
135+
122136
return;
123137
}
124138

139+
// fill cache with found matches
125140
if (options.Action == Models.Action.NoMatch)
126141
{
127142
LogService.Log("Filling no-match cache with current results due to user request", LogLevel.Warning);
128143
CacheService.AddNoMatches(Matches);
144+
129145
return;
130146
}
131147

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
133149
if (options.Action == Models.Action.Move || options.Action == Models.Action.Bin || options.Action == Models.Action.Delete) {
134150
DeleteAction deleteAction;
135151

136152
switch (options.Action)
137153
{
138154
case Models.Action.Move:
139155
deleteAction = DeleteAction.Move;
156+
// trailing slash because target path needs to be directory
140157
if (!options.Target.EndsWith("\\") && !options.Target.EndsWith("/"))
141158
options.Target += "\\";
142159
break;
@@ -151,11 +168,13 @@ public static int Main(string[] args)
151168
List<string> processedFiles = new();
152169
Matches.ForEach(m =>
153170
{
171+
// don't delete files if the match or the file itself already has been deleted
154172
if(processedFiles.Any(p => p == m.Image1.Image.FullName || p == m.Image2.Image.FullName))
155173
return;
156174

157175
for (int i = 0; i < options.Processors.Count(); i++)
158176
{
177+
// check first distinguishable property in given processors and take action if possible
159178
int processingResult = AutoProcessorService.Processors.First(p => p.DisplayName == options.Processors.ElementAt(i)).Process(m.Image1.Image, m.Image2.Image);
160179
if (processingResult != 0)
161180
{
@@ -182,6 +201,8 @@ public static int Main(string[] args)
182201
{
183202
LogService.Log($"Error Auto-Processing current match: '{m.Image1.Image.FullName}' - '{m.Image2.Image.FullName}'", LogLevel.Error);
184203
}
204+
205+
break;
185206
}
186207
}
187208
});
@@ -194,6 +215,7 @@ public static int Main(string[] args)
194215
}
195216

196217
})
218+
// console argument parser failure (or help requested)
197219
.WithNotParsed(errors =>
198220
{
199221
Console.WriteLine(
@@ -215,7 +237,11 @@ public static int Main(string[] args)
215237
return (int)exit;
216238
}
217239

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)
219245
{
220246
if (e.Target > 0)
221247
{
@@ -230,6 +256,7 @@ public static void OnProgress(object? sender, ImageComparerEventArgs e)
230256
}
231257
}
232258

259+
233260
/*
234261
* Log implementation for console output
235262
*/

ImageComparison/Services/AutoProcessorService.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,19 @@
88

99
namespace ImageComparison.Services
1010
{
11+
/// <summary>
12+
/// Automatic processing of image matches to determine what image to move/delete
13+
/// </summary>
1114
public static class AutoProcessorService
1215
{
16+
/// <summary>
17+
/// Names of the implemented processors
18+
/// </summary>
1319
public static List<string> Supported { get => Processors.Select((p) => p.DisplayName).ToList(); }
20+
21+
/// <summary>
22+
/// Processor Implementations
23+
/// </summary>
1424
public readonly static List<AutoProcessor> Processors = new()
1525
{
1626
new(){

ImageComparison/Services/CacheService.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,16 @@
44

55
namespace ImageComparison.Services
66
{
7+
/// <summary>
8+
/// Interface Service to disk/database cache
9+
/// </summary>
710
public static class CacheService
811
{
912
private static SqliteConnection connection;
1013

14+
/// <summary>
15+
/// Ensure Directory and File for the Cache exist
16+
/// </summary>
1117
public static void Init()
1218
{
1319
try
@@ -26,6 +32,11 @@ public static void Init()
2632
}
2733
}
2834

35+
/// <summary>
36+
/// Retrieve already analysed images from cache for given hashfunction
37+
/// </summary>
38+
/// <param name="hashtype"></param>
39+
/// <returns></returns>
2940
public static List<CacheItem> GetImages(string hashtype)
3041
{
3142
List<CacheItem> images = new();
@@ -45,6 +56,12 @@ public static List<CacheItem> GetImages(string hashtype)
4556
return images;
4657
}
4758

59+
/// <summary>
60+
/// Update/Add analysation data
61+
/// </summary>
62+
/// <param name="images"></param>
63+
/// <param name="hashtype"></param>
64+
/// <param name="scantime"></param>
4865
public static void UpdateImages(List<ImageAnalysis> images, string hashtype, ulong scantime)
4966
{
5067
try
@@ -82,10 +99,16 @@ public static void UpdateImages(List<ImageAnalysis> images, string hashtype, ulo
8299
connection.Close();
83100
}
84101

102+
/// <summary>
103+
/// Add image pair determined as No-Match to cache
104+
/// </summary>
105+
/// <param name="a"></param>
106+
/// <param name="b"></param>
85107
public static void AddNoMatch(string a, string b)
86108
{
87109
try
88110
{
111+
// ensure that the images in found pair are always in the same order to prevent duplicates
89112
int order = string.Compare(a, b);
90113
if (order == 0)
91114
return;
@@ -105,6 +128,10 @@ public static void AddNoMatch(string a, string b)
105128
connection.Close();
106129
}
107130

131+
/// <summary>
132+
/// Add list of image pairs as No-Matches to cache
133+
/// </summary>
134+
/// <param name="nomatches"></param>
108135
public static void AddNoMatches(List<ImageMatch> nomatches)
109136
{
110137
try
@@ -119,6 +146,7 @@ public static void AddNoMatches(List<ImageMatch> nomatches)
119146

120147
nomatches.ForEach(nomatch =>
121148
{
149+
// ensure that the images in found pair are always in the same order to prevent duplicates
122150
string a, b;
123151
int order = string.Compare(nomatch.Image1.Image.FullName, nomatch.Image2.Image.FullName);
124152
if (order == 0)
@@ -146,6 +174,10 @@ public static void AddNoMatches(List<ImageMatch> nomatches)
146174
connection.Close();
147175
}
148176

177+
/// <summary>
178+
/// Retrieve stored No-matches from cache
179+
/// </summary>
180+
/// <returns></returns>
149181
public static List<NoMatch> GetNoMatches()
150182
{
151183
List<NoMatch> nomatches = new();
@@ -168,6 +200,9 @@ public static List<NoMatch> GetNoMatches()
168200
return nomatches;
169201
}
170202

203+
/// <summary>
204+
/// Remove all analysed image data from cache (excluding no-matches)
205+
/// </summary>
171206
public static void ClearImageCache()
172207
{
173208
try
@@ -185,6 +220,9 @@ public static void ClearImageCache()
185220
connection.Close();
186221
}
187222

223+
/// <summary>
224+
/// Remove List of image pairs determined as No-Matches
225+
/// </summary>
188226
public static void ClearNoMatchCache()
189227
{
190228
try

0 commit comments

Comments
 (0)