11using System ;
2+ using System . Collections . Concurrent ;
23using System . Collections . Generic ;
34using System . ComponentModel ;
45using System . Diagnostics ;
2021using Kantan . Net . Utilities ;
2122using Kantan . Text ;
2223using Kantan . Threading ;
24+ using SmartImage . Lib . Utilities ;
2325using static System . Runtime . InteropServices . JavaScript . JSType ;
2426
2527namespace 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}
0 commit comments