1313using SmartImage . Lib . Model ;
1414using SmartImage . Lib . Results ;
1515using static Kantan . Diagnostics . LogCategories ;
16+ using static SmartImage . Lib . Engines . Impl . Search . SauceNaoEngine . Strings ;
1617using JsonArray = System . Json . JsonArray ;
1718using JsonObject = System . Json . JsonObject ;
1819
@@ -31,9 +32,15 @@ namespace SmartImage.Lib.Engines.Impl.Search;
3132
3233public sealed class SauceNaoEngine : BaseSearchEngine , IClientSearchEngine , IConfig
3334{
34- private static readonly string [ ] Syn_Artists = { "Creator(s):" , "Creator:" , "Member:" , "Artist:" , "Author:" } ;
35- private static readonly string [ ] Syn_Characters = { "Characters:" } ;
36- private static readonly string [ ] Syn_Material = { "Material:" , "Source:" } ;
35+ internal static class Strings
36+ {
37+ public const string Twitter = "Twitter:" ;
38+ public const string TweetID = "Tweet ID:" ;
39+
40+ public static readonly string [ ] Syn_Artists = { "Creator(s):" , "Creator:" , "Member:" , "Artist:" , "Author:" } ;
41+ public static readonly string [ ] Syn_Characters = { "Characters:" } ;
42+ public static readonly string [ ] Syn_Material = { "Material:" , "Source:" } ;
43+ }
3744
3845 private const string BASE_URL = "https://saucenao.com/" ;
3946
@@ -182,131 +189,135 @@ private async Task<IEnumerable<SauceNaoDataResult>> GetWebResultsAsync(SearchQue
182189
183190 var results = doc . Body . SelectNodes ( "//div[@class='result']" ) ;
184191
185- static SauceNaoDataResult Parse ( INode result )
186- {
187- if ( result == null ) {
188- return null ;
189- }
192+ return results . Select ( Parse ) . ToList ( ) ;
193+ }
190194
191- const string HIDDEN_ID_VAL = "result-hidden-notification" ;
195+ private static SauceNaoDataResult Parse ( INode result )
196+ {
197+ // TODO: OPTIMIZE
192198
193- if ( result . TryGetAttribute ( Serialization . Atr_id ) == HIDDEN_ID_VAL ) {
194- return null ;
195- }
199+ if ( result == null ) {
200+ return null ;
201+ }
196202
197- var resulttablecontent = result . FirstChild
198- . FirstChild
199- . FirstChild
200- . ChildNodes [ 1 ] ;
203+ const string HIDDEN_ID_VAL = "result-hidden-notification" ;
201204
202- var resultmatchinfo = resulttablecontent . FirstChild ;
203- var resultsimilarityinfo = resultmatchinfo . FirstChild ;
205+ if ( result . TryGetAttribute ( Serialization . Atr_id ) == HIDDEN_ID_VAL ) {
206+ return null ;
207+ }
204208
205- // Contains links
206- var resultmiscinfo = resultmatchinfo . ChildNodes [ 1 ] ;
207- // var resultcontent = resulttablecontent.ChildNodes[1];
208- // var resultcontentcolumn = resultcontent.ChildNodes[1];
209- var resultcontent = ( ( IElement ) result ) . GetElementsByClassName ( "resultcontent" ) [ 0 ] ;
209+ var resulttablecontent = result . FirstChild
210+ . FirstChild
211+ . FirstChild
212+ . ChildNodes [ 1 ] ;
210213
211- IHtmlCollection < IElement > resultcontentcolumn_rg = null ;
214+ var resultmatchinfo = resulttablecontent . FirstChild ;
215+ var resultsimilarityinfo = resultmatchinfo . FirstChild ;
212216
213- if ( result is IElement { } elem ) {
214- resultcontentcolumn_rg = elem . QuerySelectorAll ( Serialization . S_SauceNao_ResultContentColumn ) ;
217+ // Contains links
218+ var resultmiscinfo = resultmatchinfo . ChildNodes [ 1 ] ;
219+ // var resultcontent = resulttablecontent.ChildNodes[1];
220+ // var resultcontentcolumn = resultcontent.ChildNodes[1];
221+ var resultcontent = ( ( IElement ) result ) . GetElementsByClassName ( "resultcontent" ) [ 0 ] ;
215222
216- }
217- // var resulttitle = resultcontent.ChildNodes[0];
223+ IHtmlCollection < IElement > resultcontentcolumn_rg = null ;
218224
219- var links = new List < string > ( ) ;
225+ if ( result is IElement { } elem ) {
226+ resultcontentcolumn_rg = elem . QuerySelectorAll ( Serialization . S_SauceNao_ResultContentColumn ) ;
220227
221- if ( resulttablecontent is IElement { } e ) {
222- var links1 = e . QuerySelectorAll ( Serialization . Tag_a )
223- . Select ( x => x . GetAttribute ( Serialization . Atr_href ) ) ;
224- links . AddRange ( links1 ) ;
225- }
228+ }
229+ // var resulttitle = resultcontent.ChildNodes[0];
226230
227- var element = resultcontentcolumn_rg . Select ( c => c . ChildNodes )
228- . SelectMany ( c => c . GetElementsByTagName ( Serialization . Tag_a )
229- . Select ( x => x . GetAttribute ( Serialization . Atr_href ) ) )
230- . Where ( e => e != null ) ;
231+ var links = new List < string > ( ) ;
231232
232- if ( element . Any ( ) ) {
233- links . AddRange ( element ) ;
234- }
233+ if ( resulttablecontent is IElement { } e ) {
234+ var links1 = e . QuerySelectorAll ( Serialization . Tag_a )
235+ . Select ( x => x . GetAttribute ( Serialization . Atr_href ) ) ;
236+ links . AddRange ( links1 ) ;
237+ }
235238
236- if ( resultmiscinfo != null ) {
237- links . Add ( resultmiscinfo . ChildNodes . GetElementsByTagName ( Serialization . Tag_a )
238- . FirstOrDefault ( x => x . GetAttribute ( Serialization . Atr_href ) != null ) ?
239- . GetAttribute ( Serialization . Atr_href ) ) ;
240- }
239+ var element = resultcontentcolumn_rg . Select ( c => c . ChildNodes )
240+ . SelectMany ( c => c . GetElementsByTagName ( Serialization . Tag_a )
241+ . Select ( x => x . GetAttribute ( Serialization . Atr_href ) ) )
242+ . Where ( ec => ec != null ) ;
241243
242- // //div[contains(@class, 'resulttitle')]
243- // //div/node()[self::strong]
244+ if ( element . Any ( ) ) {
245+ links . AddRange ( element ) ;
246+ }
244247
245- INode resulttitle = resultcontent . ChildNodes [ 0 ] ;
246- string rti = resulttitle ? . TextContent ;
248+ if ( resultmiscinfo != null ) {
249+ links . Add ( resultmiscinfo . ChildNodes . GetElementsByTagName ( Serialization . Tag_a )
250+ . FirstOrDefault ( x => x . GetAttribute ( Serialization . Atr_href ) != null ) ?
251+ . GetAttribute ( Serialization . Atr_href ) ) ;
252+ }
247253
248- // INode resultcontentcolumn1 = resultcontent.ChildNodes[1];
249- string rcci = resultcontentcolumn_rg . FuncJoin ( e => e . TextContent , "," ) ;
254+ // //div[contains(@class, 'resulttitle')]
255+ // //div/node()[self::strong]
250256
251- // string material1 = rcci.SubstringAfter(material) ;
252- string material1 = rcci . SubstringAfter ( Syn_Material . First ( ) ) ;
257+ INode resulttitle = resultcontent . ChildNodes [ 0 ] ;
258+ string rti = resulttitle ? . TextContent ;
253259
254- // string creator1 = rcci;
255- string creator1 = rcci ;
256- string characters1 = null ;
260+ // INode resultcontentcolumn1 = resultcontent.ChildNodes[1];
261+ string rcci = resultcontentcolumn_rg . FuncJoin ( e => e . TextContent , "," ) ;
257262
258- foreach ( var s in Syn_Artists ) {
259- if ( rti . StartsWith ( s ) ) {
260- rti = rti . SubstringAfter ( s ) . Trim ( ' ' ) ;
261- }
262- }
263+ // string material1 = rcci.SubstringAfter(material);
264+ string material1 = rcci . SubstringAfter ( Syn_Material . First ( ) ) ;
263265
264- var nodes = resultcontentcolumn_rg . SelectMany ( e => e . ChildNodes )
265- . Where ( c => c is not ( IElement { TagName : "BR" }
266- or IElement { NodeName : "SPAN" } ) )
267- . ToArray ( ) ;
266+ // string creator1 = rcci;
267+ string creator1 = rcci ;
268+ string characters1 = null ;
268269
269- float similarity = float . Parse ( resultsimilarityinfo . TextContent . Replace ( "%" , string . Empty ) ) ;
270+ foreach ( var s in Syn_Artists ) {
271+ if ( rti . StartsWith ( s ) ) {
272+ rti = rti . SubstringAfter ( s ) . Trim ( ' ' ) ;
273+ }
274+ }
270275
271- var dataResult = new SauceNaoDataResult
272- {
273- Urls = links . Distinct ( ) . ToArray ( ) ,
274- Similarity = similarity ,
275- // Creator = creator1,
276- Title = rti ,
277- Material = material1
276+ var nodes = resultcontentcolumn_rg . SelectMany ( e => e . ChildNodes )
277+ . Where ( c => c is not ( IElement { TagName : "BR" }
278+ or IElement { NodeName : "SPAN" } ) )
279+ . ToArray ( ) ;
278280
279- } ;
281+ float similarity = float . Parse ( resultsimilarityinfo . TextContent . Replace ( "%" , string . Empty ) ) ;
282+
283+ var sndr = new SauceNaoDataResult
284+ {
285+ Urls = links . Distinct ( ) . ToArray ( ) ,
286+ Similarity = similarity ,
287+ // Creator = creator1,
288+ Title = rti ,
289+ Material = material1
280290
281- for ( int i = 0 ; i < nodes . Length ; i ++ ) {
282- var node = nodes [ i ] ;
283- var s = node . TextContent ;
291+ } ;
284292
285- if ( s . StartsWith ( Syn_Material [ 0 ] ) ) {
286- dataResult . Source = nodes [ ++ i ] . TextContent . Trim ( ' ' ) ;
287- continue ;
288- }
293+ for ( int i = 0 ; i < nodes . Length ; i ++ ) {
294+ var node = nodes [ i ] ;
295+ var s = node . TextContent ;
289296
290- if ( s . StartsWith ( Syn_Material [ 1 ] ) ) {
291- dataResult . Material = nodes [ ++ i ] . TextContent . Trim ( ' ' ) ;
292- continue ;
293- }
297+ if ( s . StartsWith ( Syn_Material [ 0 ] ) ) {
298+ sndr . Source = nodes [ ++ i ] . TextContent . Trim ( ' ' ) ;
299+ continue ;
300+ }
294301
295- if ( Syn_Characters . Any ( s . StartsWith ) ) {
296- dataResult . Character = nodes [ ++ i ] . TextContent . Trim ( ' ' ) ;
297- continue ;
298- }
302+ if ( s . StartsWith ( Syn_Material [ 1 ] ) ) {
303+ sndr . Material = nodes [ ++ i ] . TextContent . Trim ( ' ' ) ;
304+ continue ;
305+ }
299306
300- if ( Syn_Artists . Any ( s . StartsWith ) ) {
301- dataResult . Creator = nodes [ ++ i ] . TextContent . Trim ( ' ' ) ;
302- }
307+ if ( Syn_Characters . Any ( s . StartsWith ) || Syn_Artists . Any ( s . StartsWith ) ) {
308+ sndr . Character = nodes [ ++ i ] . TextContent . Trim ( ' ' ) ;
309+ continue ;
303310 }
304311
305- return dataResult ;
312+ if ( s . StartsWith ( Twitter ) ) {
313+ sndr . Creator = nodes [ ++ i ] . TextContent . Trim ( ' ' ) ;
314+ // var idx = Array.IndexOf(sndr.Urls, nodes[i].TryGetAttribute(Serialization.Atr_href));
315+ continue ;
316+ }
306317
307318 }
308319
309- return results . Select ( Parse ) . ToList ( ) ;
320+ return sndr ;
310321 }
311322
312323 private async Task < IEnumerable < SauceNaoDataResult > > GetAPIResultsAsync ( SearchQuery url )
@@ -323,8 +334,8 @@ private async Task<IEnumerable<SauceNaoDataResult>> GetAPIResultsAsync(SearchQue
323334 { "db" , dbIndex } ,
324335 { "output_type" , "2" } ,
325336 { "api_key" , Authentication } ,
326- { "url" , url . ToString ( ) } ,
327- { "numres" , numRes }
337+ { "url" , url . Upload } ,
338+ // { "numres", numRes }
328339 } ;
329340
330341 var content = new FormUrlEncodedContent ( values ) ;
@@ -436,18 +447,16 @@ public SearchResultItem Convert(SearchResult r)
436447 var idxStr = Index . ToString ( ) ;
437448 string siteName = Index != 0 ? idxStr : null ;
438449
439- var site = Strings . NormalizeNull ( siteName ) ;
440- var title = Strings . NormalizeNull ( WebsiteTitle ) ;
450+ var site = Kantan . Text . Strings . NormalizeNull ( siteName ) ;
451+ var title = Kantan . Text . Strings . NormalizeNull ( WebsiteTitle ) ;
441452
442453 var sb = new StringBuilder ( ) ;
443454
444- if ( site is { } )
445- {
455+ if ( site is { } ) {
446456 sb . Append ( site ) ;
447457 }
448458
449- if ( title is { } )
450- {
459+ if ( title is { } ) {
451460 sb . Append ( $ " [{ title } ]") ;
452461 }
453462
@@ -458,25 +467,25 @@ public SearchResultItem Convert(SearchResult r)
458467 Url u = s;
459468 return u.Host == "gelbooru" || u.Host == "danbooru";
460469 }).ToArray();*/
461-
462- var urls = Urls . Distinct ( ) . Where ( s => ! string . IsNullOrWhiteSpace ( s ) ) . ToArray ( ) ;
470+
471+ string [ ] urls = ( Urls != null ) ? Urls . Distinct ( ) . Where ( s => ! string . IsNullOrWhiteSpace ( s ) ) . ToArray ( ) : Array . Empty < string > ( ) ;
472+
463473 string [ ] meta = Array . Empty < string > ( ) ;
464474
465- if ( ( urls . Length >= 2 ) )
466- {
467- meta = urls [ 1 ..] . Where ( u => ! ( ( Url ) u ) . QueryParams . Contains ( "lookup_type" ) ) . ToArray ( ) ;
475+ if ( ( urls . Length >= 2 ) ) {
476+ meta = urls [ 1 ..] . Where ( u => ! ( ( Url ) u ) . QueryParams . Contains ( "lookup_type" ) ) . ToArray ( ) ;
468477 }
469478
470479 var imageResult = new SearchResultItem ( r )
471480 {
472481 Url = urls . FirstOrDefault ( ) ,
473482 Similarity = Math . Round ( Similarity , 2 ) ,
474- Description = Strings . NormalizeNull ( idxStr ) ,
475- Artist = Strings . NormalizeNull ( Creator ) ,
476- Source = Strings . NormalizeNull ( Material ) ,
477- Character = Strings . NormalizeNull ( Character ) ,
483+ Description = Kantan . Text . Strings . NormalizeNull ( idxStr ) ,
484+ Artist = Kantan . Text . Strings . NormalizeNull ( Creator ) ,
485+ Source = Kantan . Text . Strings . NormalizeNull ( Material ) ,
486+ Character = Kantan . Text . Strings . NormalizeNull ( Character ) ,
478487 Site = site ,
479- Title = Strings . NormalizeNull ( Title ) ,
488+ Title = Kantan . Text . Strings . NormalizeNull ( Title ) ,
480489 Metadata = meta ,
481490 } ;
482491
0 commit comments