Skip to content

Commit 3570d83

Browse files
committed
Work on Google Lens
1 parent 86501e7 commit 3570d83

File tree

6 files changed

+226
-9
lines changed

6 files changed

+226
-9
lines changed

SmartImage.Lib/Engines/BaseSearchEngine.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ public static IEnumerable<BaseSearchEngine> GetSelectedEngines(SearchEngineOptio
139139
if (options.HasFlag(SearchEngineOptions.Fluffle))
140140
yield return new FluffleEngine();
141141

142+
if (options.HasFlag(SearchEngineOptions.GoogleLens))
143+
yield return new GoogleLensEngine();
142144
}
143145

144146
/*public Task<SearchResult> GetTaskAsync(SearchQuery query, CancellationToken token = default)

SmartImage.Lib/Engines/Impl/Search/ArchiveMoeEngine.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ protected override ValueTask<SearchResultItem> ParseResultItem(INode n, SearchRe
7272
return ValueTask.FromResult(p.Convert(r));
7373

7474
// ReSharper restore PossibleNullReferenceException
75-
7675
}
7776

7877
protected static string GetHash(SearchQuery q)

SmartImage.Lib/Engines/Impl/Search/EHentaiEngine.cs

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -188,12 +188,13 @@ public async ValueTask<bool> ApplyCookiesAsync(CancellationToken ct = default)
188188

189189
foreach (var bck in cookies) {
190190

191-
var cookie = bck.AsCookie();
191+
var cookie = bck.AsCookie();
192192

193193
if (cookie == null) {
194194
continue;
195195
}
196-
bool c = false;
196+
197+
bool c = false;
197198

198199
if (UseExHentai) {
199200
c |= cookie.Domain.Contains(HOST_EX);
@@ -213,6 +214,51 @@ public async ValueTask<bool> ApplyCookiesAsync(CancellationToken ct = default)
213214
return IsLoggedIn = response.ResponseMessage.IsSuccessStatusCode;
214215
}
215216

217+
public async Task<bool> LoginAsync(string username, string password)
218+
{
219+
/*
220+
if (IsLoggedIn) {
221+
return false;
222+
}
223+
*/
224+
225+
// var fcc = await ReadCookiesAsync();
226+
227+
var content = new MultipartFormDataContent()
228+
{
229+
{ new StringContent("1"), "CookieDate" },
230+
{ new StringContent("d"), "b" },
231+
{ new StringContent("1-6"), "bt" },
232+
{ new StringContent(username), "UserName" },
233+
{ new StringContent(password), "PassWord" },
234+
{ new StringContent("Login!"), "ipb_login_submit" }
235+
};
236+
237+
var response = await EHentaiIndex
238+
.SetQueryParams(new
239+
{
240+
act = "Login",
241+
CODE = 01
242+
}).WithHeaders(new
243+
{
244+
User_Agent = HttpUtilities.UserAgent
245+
})
246+
.WithCookies(out var cj)
247+
.PostAsync(content);
248+
249+
/*foreach (var fc in fcc) {
250+
Cookies.Add(fc.AsCookie());
251+
}*/
252+
253+
foreach (var fc in response.Cookies) {
254+
Jar.AddOrReplace(fc);
255+
}
256+
257+
var res2 = await GetSessionAsync();
258+
259+
return IsLoggedIn = res2.ResponseMessage.IsSuccessStatusCode;
260+
}
261+
216262
/*
217263
* https://gitlab.com/NekoInverter/EhViewer/-/tree/master/app/src/main/java/com/hippo/ehviewer/client
218264
* https://gitlab.com/NekoInverter/EhViewer/-/tree/master/app/src/main/java/com/hippo/ehviewer
@@ -239,7 +285,7 @@ public ValueTask<bool> ApplyConfigAsync(SearchConfig cfg, CancellationToken ct =
239285

240286
public ICookiesProvider Provider { get; set; }
241287

242-
#region
288+
#region
243289

244290
public static readonly Url EHentaiIndex = "https://forums.e-hentai.org/index.php";
245291
public static readonly Url EHentaiBase = "https://e-hentai.org/";
@@ -248,14 +294,14 @@ public ValueTask<bool> ApplyConfigAsync(SearchConfig cfg, CancellationToken ct =
248294
public static readonly Url ExHentaiBase = "https://exhentai.org/";
249295
public static readonly Url ExHentaiLookup = "https://upld.exhentai.org/upld/image_lookup.php";
250296

251-
#region
297+
#region
252298

253299
private const string HOST_EH = ".e-hentai.org";
254300
private const string HOST_EX = ".exhentai.org";
255301

256-
#endregion
302+
#endregion
257303

258-
#endregion
304+
#endregion
259305

260306
protected override ValueTask<SearchResultItem> ParseResultItem(INode n, SearchResult r)
261307
{
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
// Author: Deci | Project: SmartImage.Lib | Name: GoogleLens.cs
2+
// Date: 2025/04/15 @ 11:04:23
3+
4+
using AngleSharp;
5+
using AngleSharp.Css.Values;
6+
using AngleSharp.Dom;
7+
using AngleSharp.Html.Parser;
8+
using Flurl.Http;
9+
using Kantan.Net.Utilities;
10+
using SmartImage.Lib.Images.Uni;
11+
using SmartImage.Lib.Results;
12+
13+
namespace SmartImage.Lib.Engines.Impl.Search;
14+
15+
public class GoogleLensEngine : WebSearchEngine, IEndpointEngine
16+
{
17+
18+
// TODO: WIP
19+
20+
public const string URL_BASE = "https://lens.google.com";
21+
22+
public override string Name => "Google Lens";
23+
24+
public override Url BaseUrl => URL_BASE;
25+
26+
public override SearchEngineOptions EngineOption => SearchEngineOptions.GoogleLens;
27+
28+
protected override string NodesSelector => throw new NotImplementedException();
29+
30+
public Url EndpointUrl => URL_BASE;
31+
32+
public GoogleLensEngine() : base(URL_BASE) { }
33+
34+
public static readonly string[] SearchTypes = ["all", "products", "visual_matches", "exact_matches"];
35+
36+
public FlurlCookie Nid { get; set; }
37+
38+
public string HlParam { get; set; } = "en-US";
39+
40+
public string SearchType { get; set; } = SearchTypes[0];
41+
42+
public object Headers = new
43+
{
44+
User_Agent = HttpUtilities.UserAgent,
45+
Connection = "keep-alive",
46+
Accept_Encoding = "gzip, deflate, br",
47+
Accept = "*/*"
48+
};
49+
50+
protected override async ValueTask<SearchResultItem> ParseResultItem(INode n, SearchResult r)
51+
{
52+
throw new NotImplementedException();
53+
}
54+
55+
public override async Task<SearchResult> GetResultAsync(SearchQuery query, CancellationToken token = default)
56+
{
57+
return await base.GetResultAsync(query, token);
58+
}
59+
60+
protected override async Task<IDocument> GetDocumentAsync(SearchResult sr, SearchQuery query, CancellationToken token = default)
61+
{
62+
string endpoint, filename;
63+
Task<IFlurlResponse> req;
64+
IFlurlResponse res;
65+
66+
/*if (query.Source.IsFile) {
67+
req = SearchFile(query, token);
68+
}
69+
else if (query.Source.IsUri) {
70+
req = SearchUrl(query, token);
71+
}
72+
else {
73+
return null;
74+
}*/
75+
76+
req = SearchUrlAsync(query, token);
77+
78+
res = await req;
79+
80+
// var stream = await res.GetStringAsync();
81+
var url = res.ResponseMessage.RequestMessage.RequestUri;
82+
83+
var res2 = await Client.Request(url)
84+
.WithTimeout(Timeout)
85+
// .WithHeaders(Headers)
86+
.WithCookie(Nid.Name, Nid.Value)
87+
.GetAsync(cancellationToken: token);
88+
89+
var resData = await res2.GetStringAsync();
90+
91+
var parser = new HtmlParser(new HtmlParserOptions()
92+
{
93+
IsScripting = true,
94+
IsStrictMode = false,
95+
IsAcceptingCustomElementsEverywhere = true,
96+
IsEmbedded = true
97+
});
98+
99+
var doc = await parser.ParseDocumentAsync(resData);
100+
101+
// BrowsingContext.New(Configuration.Default.WithCookies().WithCss());
102+
103+
return doc;
104+
}
105+
106+
private Task<IFlurlResponse> SearchFileAsync(SearchQuery query, CancellationToken token)
107+
{
108+
string endpoint;
109+
string filename;
110+
UniImageFile uif = query.Source as UniImageFile;
111+
Task<IFlurlResponse> req;
112+
endpoint = "v3/upload";
113+
114+
// filename = "image.jpg";
115+
// filename = (query.Source is UniImageFile uif) ? uif.FileInfo.Name : "image.jpg";
116+
filename = uif.FileInfo.Name;
117+
118+
req = Client.Request(EndpointUrl, endpoint)
119+
.SetQueryParam("hl", HlParam)
120+
.WithTimeout(Timeout)
121+
.WithCookie(Nid.Name, Nid.Value)
122+
.WithHeaders(Headers)
123+
.PostMultipartAsync(bc =>
124+
{
125+
//
126+
bc.AddFile(filename, uif.FilePath);
127+
}, cancellationToken: token);
128+
129+
return req;
130+
}
131+
132+
private Task<IFlurlResponse> SearchUrlAsync(SearchQuery query, CancellationToken token)
133+
{
134+
return SearchUrlAsync(query.Upload, token);
135+
}
136+
137+
private Task<IFlurlResponse> SearchUrlAsync(Url url, CancellationToken token)
138+
{
139+
string endpoint;
140+
Task<IFlurlResponse> req;
141+
endpoint = "uploadbyurl";
142+
143+
req = Client.Request(EndpointUrl, endpoint)
144+
.SetQueryParam("hl", HlParam)
145+
.SetQueryParam("url", url)
146+
.WithCookie(Nid.Name, Nid.Value)
147+
.WithHeaders(Headers)
148+
.WithTimeout(Timeout)
149+
.GetAsync(cancellationToken: token);
150+
return req;
151+
}
152+
153+
protected override async ValueTask<List<INode>> GetNodes(IDocument d)
154+
{
155+
return await base.GetNodes(d);
156+
}
157+
158+
protected override Url GetRawUrl(SearchQuery query)
159+
{
160+
return base.GetRawUrl(query);
161+
}
162+
163+
public override void Dispose() { }
164+
165+
}

SmartImage.Lib/Engines/Impl/Search/IqdbEngine.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ public override async Task<SearchResult> GetResultAsync(SearchQuery query, Cance
240240

241241
var doc = await GetDocumentAsync(query, token);
242242

243-
if (doc == null || doc.Body == null) {
243+
if (doc?.Body == null) {
244244
sr.ErrorMessage = "Could not retrieve data";
245245
sr.Status = SearchResultStatus.UnknownError;
246246
goto ret;

SmartImage.Lib/Engines/SearchEngineOptions.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,14 +97,19 @@ public enum SearchEngineOptions
9797
/// </summary>
9898
Fluffle = 1 << 15,
9999

100+
/// <summary>
101+
/// <see cref="GoogleLensEngine"/>
102+
/// </summary>
103+
GoogleLens = 1 << 16,
104+
100105

101106
#region
102107

103108
/// <summary>
104109
/// All engines
105110
/// </summary>
106111
All = SauceNao | ImgOps | GoogleImages | TinEye | Iqdb | TraceMoe | KarmaDecay | Yandex | Bing |
107-
Ascii2D | RepostSleuth | EHentai | ArchiveMoe | Iqdb3D | Fluffle,
112+
Ascii2D | RepostSleuth | EHentai | ArchiveMoe | Iqdb3D | Fluffle | GoogleLens,
108113

109114
Artwork = SauceNao | Iqdb | Ascii2D | EHentai,
110115

0 commit comments

Comments
 (0)