Skip to content

Commit 5dcedc5

Browse files
committed
...
1 parent ae946ce commit 5dcedc5

File tree

6 files changed

+146
-137
lines changed

6 files changed

+146
-137
lines changed

SmartImage.Lib 3/Engines/BaseSearchEngine.cs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,7 @@ protected BaseSearchEngine(string baseUrl)
3838
BaseUrl = baseUrl;
3939
}
4040

41-
static BaseSearchEngine()
42-
{
43-
}
41+
static BaseSearchEngine() { }
4442

4543
protected virtual bool Verify(SearchQuery q)
4644
{
@@ -75,7 +73,7 @@ public virtual async Task LoadAsync(SearchConfig cfg)
7573

7674
if (e is { IsLoggedIn: true }) {
7775
Debug.WriteLine($"{this.Name} is already logged in", nameof(LoadAsync));
78-
76+
7977
return;
8078
}
8179

@@ -128,12 +126,8 @@ protected virtual ValueTask<Url> GetRawUrlAsync(SearchQuery query)
128126
return ValueTask.FromResult(u);
129127
}
130128

131-
#region Implementation of IDisposable
132-
133129
public abstract void Dispose();
134130

135-
#endregion
136-
137131
public static readonly BaseSearchEngine[] All =
138132
ReflectionHelper.CreateAllInAssembly<BaseSearchEngine>(TypeProperties.Subclass).ToArray();
139133
}

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

Lines changed: 100 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Concurrent;
23
using System.Collections.Generic;
34
using System.ComponentModel;
45
using System.Diagnostics;
@@ -20,6 +21,7 @@
2021
using Kantan.Net.Utilities;
2122
using Kantan.Text;
2223
using Kantan.Threading;
24+
using SmartImage.Lib.Utilities;
2325
using static System.Runtime.InteropServices.JavaScript.JSType;
2426

2527
namespace SmartImage.Lib.Engines.Search;
@@ -44,31 +46,17 @@ public sealed class EHentaiEngine : WebSearchEngine, ILoginEngine, INotifyProper
4446

4547
#region Url
4648

47-
private const string EHENTAI_INDEX_URI = "https://forums.e-hentai.org/index.php";
49+
private static readonly Url EHentaiIndex = "https://forums.e-hentai.org/index.php";
4850

49-
private const string EXHENTAI_URI = "https://exhentai.org/";
50-
private const string EHENTAI_URI = "https://e-hentai.org/";
51+
public static readonly Url ExHentaiBase = "https://exhentai.org/";
52+
public static readonly Url EHentaiBase = "https://e-hentai.org/";
5153

52-
private static readonly Url ExHentai_Image_Lookup = Url.Combine(EXHENTAI_URI, "upld", "image_lookup.php");
54+
private static readonly Url ExHentaiLookup = Url.Combine(ExHentaiBase, "upld", "image_lookup.php");
55+
private static readonly Url EHentaiLookup = "https://upld.e-hentai.org/image_lookup.php";
5356

54-
public override Url BaseUrl
55-
{
56-
get { return IsLoggedIn ? EXHENTAI_URI : EHENTAI_URI; }
57-
}
57+
public override Url BaseUrl => IsLoggedIn ? ExHentaiBase : EHentaiBase;
5858

59-
private Url Lookup
60-
{
61-
get
62-
{
63-
if (IsLoggedIn) {
64-
return ExHentai_Image_Lookup;
65-
}
66-
else {
67-
return "https://upld.e-hentai.org/image_lookup.php";
68-
69-
}
70-
}
71-
}
59+
private Url LookupUrl => IsLoggedIn ? ExHentaiLookup : EHentaiLookup;
7260

7361
#endregion
7462

@@ -80,12 +68,20 @@ private Url Lookup
8068

8169
static EHentaiEngine() { }
8270

83-
public EHentaiEngine() : base(EHENTAI_URI)
71+
public EHentaiEngine() : base(EHentaiBase)
8472
{
8573
m_client = new HttpClient(m_clientHandler);
8674
Cookies = new CookieJar();
8775
IsLoggedIn = false;
8876

77+
PropertyChanged += (sender, args) =>
78+
{
79+
if (IsLoggedIn) {
80+
IsLoggedIn = false;
81+
}
82+
83+
Trace.WriteLine($"{IsLoggedIn} - {args.PropertyName}", nameof(PropertyChanged));
84+
};
8985
}
9086

9187
/*
@@ -108,6 +104,7 @@ protected override async Task<IDocument> GetDocumentAsync(object origin, SearchQ
108104
if (b) {
109105
Trace.WriteLine($"allocated {t}", nameof(GetDocumentAsync));
110106
}
107+
111108
var data = new MultipartFormDataContent()
112109
{
113110
{ new FileContent(t), "sfile", name },
@@ -149,8 +146,9 @@ protected override async Task<IDocument> GetDocumentAsync(object origin, SearchQ
149146
m_clientHandler.CookieContainer.Add(new Cookie(c.Name, c.Value, c.Path, c.Domain));
150147
}
151148

152-
Debug.WriteLine($"{Lookup}", nameof(GetDocumentAsync));
153-
var req = new HttpRequestMessage(HttpMethod.Post, Lookup)
149+
Debug.WriteLine($"{LookupUrl}", nameof(GetDocumentAsync));
150+
151+
var req = new HttpRequestMessage(HttpMethod.Post, LookupUrl)
154152
{
155153
Content = data,
156154
Headers =
@@ -174,7 +172,7 @@ protected override async Task<IDocument> GetDocumentAsync(object origin, SearchQ
174172

175173
private async Task<IFlurlResponse> GetSessionAsync()
176174
{
177-
return await EXHENTAI_URI.WithCookies(Cookies)
175+
return await ExHentaiBase.WithCookies(Cookies)
178176
.WithHeaders(new
179177
{
180178
User_Agent = HttpUtilities.UserAgent
@@ -201,7 +199,7 @@ protected override ValueTask<SearchResultItem> ParseNodeToItem(INode n, SearchRe
201199
var item = new SearchResultItem(r)
202200
{ };
203201

204-
EhResult eh = GetEhResult(n);
202+
var eh = EhResult.Parse(n);
205203

206204
if (eh.Tags.TryGetValue("artist", out var v)) {
207205
item.Artist = v.FirstOrDefault();
@@ -220,75 +218,6 @@ protected override ValueTask<SearchResultItem> ParseNodeToItem(INode n, SearchRe
220218
return ValueTask.FromResult(item);
221219
}
222220

223-
private static EhResult GetEhResult(INode n)
224-
{
225-
// ReSharper disable InconsistentNaming
226-
var eh = new EhResult();
227-
228-
var gl1c = n.ChildNodes.FirstOrDefault(f => f is IElement { ClassName: "gl1c" } e);
229-
230-
if (gl1c is { }) {
231-
if (gl1c.FirstChild is { } t) {
232-
eh.Type = t.TextContent;
233-
}
234-
}
235-
236-
var gl2c = n.ChildNodes.FirstOrDefault(f => f is IElement { ClassName: "gl2c" } e);
237-
238-
if (gl2c is { }) {
239-
if (gl2c.ChildNodes[1].ChildNodes[1].ChildNodes[1].ChildNodes[1] is { } div) {
240-
eh.Pages = div.TextContent;
241-
}
242-
}
243-
244-
var gl3c = n.ChildNodes.FirstOrDefault(f => f is IElement { ClassName: "gl3c glname" } e);
245-
246-
if (gl3c is { }) {
247-
if (gl3c.FirstChild is { } f) {
248-
eh.Url = (Url) f.TryGetAttribute(Serialization.Atr_href);
249-
250-
if (f.FirstChild is { } ff) {
251-
eh.Title = ff.TextContent;
252-
}
253-
254-
if (f.ChildNodes[1] is { ChildNodes: { Length: > 0 } cn } f2) {
255-
var tagValuesRaw = cn.Select(c => c.TryGetAttribute("title"));
256-
257-
foreach (string s in tagValuesRaw) {
258-
var split = s.Split(':');
259-
var tag = split[0];
260-
var val = split[1];
261-
262-
if (eh.Tags.ContainsKey(tag)) {
263-
eh.Tags[tag].Add(val);
264-
}
265-
else {
266-
eh.Tags.Add(tag, new() { val });
267-
268-
}
269-
}
270-
}
271-
}
272-
}
273-
274-
var gl4c = n.ChildNodes.FirstOrDefault(f => f is IElement { ClassName: "gl4c glhide" } e);
275-
276-
if (gl4c is { }) {
277-
if (gl4c.ChildNodes[0] is { FirstChild: { } div1 } div1Outer) {
278-
eh.AuthorUrl = div1.TryGetAttribute(Serialization.Atr_href);
279-
eh.Author = div1Outer.TextContent ?? div1.TextContent;
280-
}
281-
282-
if (gl4c.ChildNodes[1] is { } div2) {
283-
eh.Pages ??= div2.TextContent;
284-
}
285-
}
286-
287-
return eh;
288-
289-
// ReSharper restore InconsistentNaming
290-
}
291-
292221
public override void Dispose()
293222
{
294223
m_client.Dispose();
@@ -341,7 +270,7 @@ public async Task<bool> LoginAsync()
341270
{ new StringContent("Login!"), "ipb_login_submit" }
342271
};
343272

344-
var response = await EHENTAI_INDEX_URI
273+
var response = await EHentaiIndex
345274
.SetQueryParams(new
346275
{
347276
act = "Login",
@@ -381,7 +310,7 @@ private bool SetField<T>(ref T field, T value, [CallerMemberName] string propert
381310

382311
#endregion
383312

384-
private sealed record EhResult
313+
private sealed record EhResult : IParseable<EhResult, INode>
385314
{
386315
internal string Type { get; set; }
387316
internal string Pages { get; set; }
@@ -390,6 +319,79 @@ private sealed record EhResult
390319
internal string AuthorUrl { get; set; }
391320
internal Url Url { get; set; }
392321

393-
internal Dictionary<string, List<string>> Tags { get; set; } = new();
322+
internal ConcurrentDictionary<string, ConcurrentBag<string>> Tags { get; } = new();
323+
324+
public static EhResult Parse(INode n)
325+
{
326+
// ReSharper disable InconsistentNaming
327+
var eh = new EhResult();
328+
329+
var gl1c = n.ChildNodes.TryFindElementByClassName("gl1c");
330+
331+
if (gl1c is { }) {
332+
if (gl1c.FirstChild is { } t) {
333+
eh.Type = t.TextContent;
334+
}
335+
}
336+
337+
var gl2c = n.ChildNodes.TryFindElementByClassName("gl2c");
338+
339+
if (gl2c is { }) {
340+
if (gl2c.ChildNodes[1].ChildNodes[1].ChildNodes[1].ChildNodes[1] is { } div) {
341+
eh.Pages = div.TextContent;
342+
}
343+
}
344+
345+
var gl3c = n.ChildNodes.TryFindElementByClassName("gl3c glname");
346+
347+
if (gl3c is { }) {
348+
if (gl3c.FirstChild is { } f) {
349+
eh.Url = (Url) f.TryGetAttribute(Serialization.Atr_href);
350+
351+
if (f.FirstChild is { } ff) {
352+
eh.Title = ff.TextContent;
353+
}
354+
355+
if (f.ChildNodes[1] is { ChildNodes: { Length: > 0 } cn } f2) {
356+
var tagValuesRaw = cn.Select(c => c.TryGetAttribute("title"));
357+
358+
foreach (string s in tagValuesRaw) {
359+
if (s is not { }) {
360+
continue;
361+
}
362+
363+
var split = s.Split(':');
364+
var tag = split[0];
365+
var val = split[1];
366+
367+
if (eh.Tags.ContainsKey(tag)) {
368+
eh.Tags[tag].Add(val);
369+
}
370+
else {
371+
eh.Tags.TryAdd(tag, new() { val });
372+
373+
}
374+
}
375+
}
376+
}
377+
}
378+
379+
var gl4c = n.ChildNodes.TryFindElementByClassName("gl4c glhide");
380+
381+
if (gl4c is { }) {
382+
if (gl4c.ChildNodes[0] is { FirstChild: { } div1 } div1Outer) {
383+
eh.AuthorUrl = div1.TryGetAttribute(Serialization.Atr_href);
384+
eh.Author = div1Outer.TextContent ?? div1.TextContent;
385+
}
386+
387+
if (gl4c.ChildNodes[1] is { } div2) {
388+
eh.Pages ??= div2.TextContent;
389+
}
390+
}
391+
392+
return eh;
393+
394+
// ReSharper restore InconsistentNaming
395+
}
394396
}
395397
}

SmartImage.Lib 3/Engines/WebSearchEngine.cs

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -61,19 +61,19 @@ protected virtual async Task<IDocument> GetDocumentAsync(object origin2, SearchQ
6161
try {
6262
if (origin2 is Url origin) {
6363
var res = await origin.WithClient(SearchClient.Client)
64-
.AllowAnyHttpStatus()
65-
.WithCookies(out var cj)
66-
.WithTimeout(Timeout)
67-
.WithHeaders(new
68-
{
69-
User_Agent = HttpUtilities.UserAgent
70-
})
71-
.WithAutoRedirect(true)
72-
/*.OnError(s =>
73-
{
74-
s.ExceptionHandled = true;
75-
})*/
76-
.GetAsync(cancellationToken: token.Value);
64+
.AllowAnyHttpStatus()
65+
.WithCookies(out var cj)
66+
.WithTimeout(Timeout)
67+
.WithHeaders(new
68+
{
69+
User_Agent = HttpUtilities.UserAgent
70+
})
71+
.WithAutoRedirect(true)
72+
/*.OnError(s =>
73+
{
74+
s.ExceptionHandled = true;
75+
})*/
76+
.GetAsync(cancellationToken: token.Value);
7777

7878
var str = await res.GetStringAsync();
7979

@@ -100,4 +100,12 @@ protected virtual ValueTask<INode[]> GetNodes(IDocument d)
100100
=> ValueTask.FromResult(d.Body.SelectNodes(NodesSelector).ToArray());
101101

102102
protected abstract string NodesSelector { get; }
103+
}
104+
105+
internal static class NodeHelper
106+
{
107+
internal static INode TryFindElementByClassName(this INodeList nodes, string className)
108+
{
109+
return nodes.FirstOrDefault(f => f is IElement e && e.ClassName == className);
110+
}
103111
}

0 commit comments

Comments
 (0)