Skip to content

Commit fd3d6de

Browse files
committed
Multithreaded searching
1 parent 065f9da commit fd3d6de

15 files changed

+267
-179
lines changed

SmartImage/Program.cs

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
using System;
44
using System.Collections.Generic;
55
using System.Diagnostics;
6+
using System.Drawing;
67
using System.IO.Compression;
78
using System.Linq;
9+
using System.Media;
810
using System.Reflection;
911
using System.Text;
1012
using System.Threading;
@@ -61,23 +63,31 @@ private static void Main(string[] args)
6163
SearchConfig.ReadSearchConfigArguments(args);
6264

6365
if (SearchConfig.Config.NoArguments) {
64-
ConsoleIO.RunMainCommandMenu();
66+
ConsoleMainMenu.RunMainMenu();
6567
Console.Clear();
6668
}
6769

6870
string img = SearchConfig.Config.Image;
6971

70-
var n = Enum.GetValues(typeof(SearchEngines)).Length;
71-
72-
ConsoleOption[] results = new SearchResult[n];
73-
var ok = Search.RunSearch(img, ref results);
74-
75-
if (!ok) {
76-
CliOutput.WriteError("Search failed or aborted");
72+
// Run checks
73+
if (!SearchClient.IsFileValid(img))
74+
{
7775
return;
7876
}
7977

80-
ConsoleIO.HandleConsoleOptions(results);
78+
// var n = Enum.GetValues(typeof(SearchEngines)).Length;
79+
// ConsoleOption[] results = new SearchResult[n];
80+
// var ok = Search.RunSearch(img, ref results);
81+
//
82+
// if (!ok) {
83+
// CliOutput.WriteError("Search failed or aborted");
84+
// return;
85+
// }
86+
87+
using var s = new SearchClient(img);
88+
s.Start();
89+
90+
ConsoleIO.HandleOptions(s.Results);
8191
}
8292
catch (Exception exception) {
8393

SmartImage/Searching/Engines/Simple/ImgOpsClient.cs renamed to SmartImage/Searching/Engines/Other/ImgOpsClient.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public sealed class ImgOpsClient : SimpleSearchEngine
1515
public ImgOpsClient() : base("http://imgops.com/") { }
1616

1717
public override string Name => "ImgOps";
18-
public override ConsoleColor Color => ConsoleColor.Magenta;
18+
public override ConsoleColor Color => ConsoleColor.DarkMagenta;
1919

2020
public override SearchEngines Engine => SearchEngines.ImgOps;
2121

SmartImage/Searching/Engines/Simple/IqdbClient.cs renamed to SmartImage/Searching/Engines/Other/IqdbClient.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public sealed class IqdbClient : SimpleSearchEngine
1919
public IqdbClient() : base("https://iqdb.org/?url=") { }
2020

2121
public override string Name => "IQDB";
22-
public override ConsoleColor Color => ConsoleColor.Magenta;
22+
public override ConsoleColor Color => ConsoleColor.DarkGreen;
2323

2424
public override SearchEngines Engine => SearchEngines.Iqdb;
2525

SmartImage/Searching/Search.cs renamed to SmartImage/Searching/SearchClient.cs

Lines changed: 67 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,8 @@
1-
#region
2-
3-
#nullable enable
4-
using System;
1+
using System;
52
using System.Collections.Generic;
6-
using System.Drawing;
73
using System.IO;
84
using System.Linq;
95
using System.Threading;
10-
using System.Threading.Tasks;
11-
using SimpleCore.Utilities;
126
using SimpleCore.Win32.Cli;
137
using SmartImage.Searching.Engines.Imgur;
148
using SmartImage.Searching.Engines.SauceNao;
@@ -18,59 +12,31 @@
1812
using SmartImage.Shell;
1913
using SmartImage.Utilities;
2014

21-
// ReSharper disable ReturnTypeCanBeEnumerable.Local
22-
23-
#endregion
24-
25-
// ReSharper disable ReturnTypeCanBeEnumerable.Global
26-
2715
namespace SmartImage.Searching
2816
{
29-
/// <summary>
30-
/// Runs image searches
31-
/// </summary>
32-
public static class Search
17+
public class SearchClient : IDisposable
3318
{
3419
/// <summary>
35-
/// Common image extensions
20+
/// Common image extensions
3621
/// </summary>
3722
private static readonly string[] ImageExtensions =
3823
{
3924
".jpg", ".jpeg", ".png", ".gif", ".tga", ".jfif", ".bmp"
4025
};
4126

27+
private readonly SearchEngines m_engines;
4228

43-
private static ISearchEngine[] GetAllEngines()
44-
{
45-
var engines = new ISearchEngine[]
46-
{
47-
new SauceNaoClient(),
48-
new ImgOpsClient(),
49-
new GoogleImagesClient(),
50-
new TinEyeClient(),
51-
new IqdbClient(),
52-
new BingClient(),
53-
new YandexClient(),
54-
new KarmaDecayClient(),
55-
new TraceMoeClient()
56-
};
57-
58-
return engines;
59-
}
29+
private readonly string m_img;
6030

31+
private readonly string m_imgUrl;
6132

62-
public static bool RunSearch(string img, ref ConsoleOption[] res)
63-
{
64-
/*
65-
* Run
66-
*/
33+
private ConsoleOption[] m_results;
6734

68-
// Run checks
69-
if (!IsFileValid(img)) {
70-
SearchConfig.UpdateFile();
35+
private readonly Thread[] m_threads;
7136

72-
return false;
73-
}
37+
public SearchClient(string img)
38+
{
39+
7440

7541
string auth = SearchConfig.Config.ImgurAuth;
7642
bool useImgur = !String.IsNullOrWhiteSpace(auth);
@@ -84,76 +50,81 @@ public static bool RunSearch(string img, ref ConsoleOption[] res)
8450
engines = SearchConfig.ENGINES_DEFAULT;
8551
}
8652

53+
m_engines = engines;
8754

88-
// Display config
89-
CliOutput.WriteInfo(SearchConfig.Config);
9055

56+
m_imgUrl = Upload(img, useImgur);
9157

92-
string imgUrl = Upload(img, useImgur);
58+
59+
m_threads = CreateSearchThreads();
60+
}
9361

94-
CliOutput.WriteInfo("Temporary image url: {0}", imgUrl);
62+
public ref ConsoleOption[] Results => ref m_results;
9563

96-
Console.WriteLine();
64+
public void Dispose()
65+
{
66+
foreach (var thread in m_threads) {
67+
thread.Join();
68+
}
69+
}
9770

71+
public void Start()
72+
{
73+
// Display config
74+
CliOutput.WriteInfo(SearchConfig.Config);
9875

99-
// Where the actual searching occurs
76+
CliOutput.WriteInfo("Temporary image url: {0}", m_imgUrl);
10077

101-
//StartSearches(imgUrl, engines, ref res);
102-
var threads = StartSearchesMultithread(imgUrl, engines, ref res);
78+
Console.WriteLine();
10379

104-
foreach (var thread in threads) {
80+
foreach (var thread in m_threads) {
10581
thread.Start();
10682
}
107-
108-
return true;
10983
}
11084

111-
11285

113-
private static Thread[] StartSearchesMultithread(string imgUrl, SearchEngines engines, ref ConsoleOption[] res)
86+
private Thread[] CreateSearchThreads()
11487
{
11588
// todo: improve
116-
// todo: use tasks
89+
11790

11891
var availableEngines = GetAllEngines()
119-
.Where(e => engines.HasFlag(e.Engine))
92+
.Where(e => m_engines.HasFlag(e.Engine))
12093
.ToArray();
12194

12295
int i = 0;
12396

124-
res = new SearchResult[availableEngines.Length + 1];
125-
res[i] = new SearchResult(ConsoleColor.Gray, "(Original image)", imgUrl, null);
97+
m_results = new ConsoleOption[availableEngines.Length + 1];
98+
m_results[i] = new SearchResult(ConsoleColor.Gray, "(Original image)", m_imgUrl);
12699

127100
i++;
128101

129102

130103
var threads = new List<Thread>();
131104

132-
foreach (var currentEngine in availableEngines)
133-
{
134-
var options = res;
105+
foreach (var currentEngine in availableEngines) {
135106

136-
int i1 = i;
107+
var resultsCopy = m_results;
108+
int iCopy = i;
137109

138-
ThreadStart ts = () =>
110+
ThreadStart threadFunction = () =>
139111
{
140-
var result = currentEngine.GetResult(imgUrl);
141-
options[i1] = result;
142-
112+
var result = currentEngine.GetResult(m_imgUrl);
113+
resultsCopy[iCopy] = result;
143114

144115
// If the engine is priority, open its result in the browser
145-
if (SearchConfig.Config.PriorityEngines.HasFlag(currentEngine.Engine))
146-
{
116+
if (SearchConfig.Config.PriorityEngines.HasFlag(currentEngine.Engine)) {
147117
Network.OpenUrl(result.Url);
148118
}
149119

150120
ConsoleIO.Status = ConsoleIO.STATUS_REFRESH;
121+
};
151122

152-
123+
var t = new Thread(threadFunction)
124+
{
125+
Priority = ThreadPriority.Highest
153126
};
154-
var t = new Thread(ts);
155-
t.Priority = ThreadPriority.Highest;
156-
t.Name = string.Format("thread - {0}", currentEngine.Name);
127+
157128
threads.Add(t);
158129

159130
i++;
@@ -164,9 +135,27 @@ private static Thread[] StartSearchesMultithread(string imgUrl, SearchEngines en
164135

165136
}
166137

167-
private static bool IsFileValid(string img)
138+
private static ISearchEngine[] GetAllEngines()
139+
{
140+
var engines = new ISearchEngine[]
141+
{
142+
new SauceNaoClient(),
143+
new ImgOpsClient(),
144+
new GoogleImagesClient(),
145+
new TinEyeClient(),
146+
new IqdbClient(),
147+
new BingClient(),
148+
new YandexClient(),
149+
new KarmaDecayClient(),
150+
new TraceMoeClient()
151+
};
152+
153+
return engines;
154+
}
155+
156+
internal static bool IsFileValid(string img)
168157
{
169-
if (string.IsNullOrWhiteSpace(img)) {
158+
if (String.IsNullOrWhiteSpace(img)) {
170159
return false;
171160
}
172161

SmartImage/Searching/SearchResult.cs

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
#nullable enable
22
using System;
33
using System.Collections.Generic;
4-
using System.Linq;
54
using System.Text;
6-
using SimpleCore.Utilities;
75
using SimpleCore.Win32.Cli;
86
using SmartImage.Searching.Model;
97
using SmartImage.Shell;
@@ -12,7 +10,7 @@
1210
namespace SmartImage.Searching
1311
{
1412
/// <summary>
15-
/// Contains search result and information
13+
/// Contains search result and information
1614
/// </summary>
1715
public sealed class SearchResult : ConsoleOption, IExtendedSearchResult
1816
{
@@ -32,33 +30,18 @@ public SearchResult(ConsoleColor color, string name, string url, float? similari
3230

3331
public override ConsoleColor Color { get; internal set; }
3432

35-
36-
/// <summary>
37-
/// Best match
38-
/// </summary>
39-
public string Url { get; }
40-
4133
// todo: create a specific url field with the original url
4234

4335
public override string? Data => Format();
4436

4537
public override string Name { get; internal set; }
4638

47-
/// <summary>
48-
/// Image similarity
49-
/// </summary>
50-
public float? Similarity { get; set; }
51-
52-
public int? Width { get; set; }
53-
public int? Height { get; set; }
54-
public string? Caption { get; set; }
55-
5639
public bool Success => Url != null;
5740

5841
public List<string> ExtendedInfo { get; }
5942

6043
/// <summary>
61-
/// Direct source matches, other extended results
44+
/// Direct source matches, other extended results
6245
/// </summary>
6346
public List<IExtendedSearchResult> ExtendedResults { get; }
6447

@@ -77,6 +60,21 @@ public override Func<object?> Function
7760
public override Func<object?>? AltFunction { get; internal set; }
7861

7962

63+
/// <summary>
64+
/// Best match
65+
/// </summary>
66+
public string Url { get; }
67+
68+
/// <summary>
69+
/// Image similarity
70+
/// </summary>
71+
public float? Similarity { get; set; }
72+
73+
public int? Width { get; set; }
74+
public int? Height { get; set; }
75+
public string? Caption { get; set; }
76+
77+
8078
private SearchResult[] FromExtendedResult(IReadOnlyList<IExtendedSearchResult> results)
8179
{
8280

@@ -113,7 +111,7 @@ public void AddExtendedInfo(IExtendedSearchResult[] bestImages)
113111
var rg = FromExtendedResult(bestImages);
114112

115113

116-
ConsoleIO.HandleConsoleOptions(rg);
114+
ConsoleIO.HandleOptions(rg);
117115

118116
return null;
119117

@@ -131,7 +129,7 @@ private string Format()
131129
var sb = new StringBuilder();
132130

133131
char success = Success ? CliOutput.RAD_SIGN : CliOutput.MUL_SIGN;
134-
string altStr = AltFunction != null ? ConsoleIO.ALT_DENOTE : string.Empty;
132+
string altStr = AltFunction != null ? ConsoleIO.ALT_DENOTE : String.Empty;
135133

136134
sb.AppendFormat("{0} {1}\n", success, altStr);
137135

0 commit comments

Comments
 (0)