File Coverage

blib/lib/Net/Async/WebSearch/Provider/SearxNG.pm
Criterion Covered Total %
statement 27 64 42.1
branch 0 28 0.0
condition 0 6 0.0
subroutine 9 14 64.2
pod 3 3 100.0
total 39 115 33.9


line stmt bran cond sub pod time code
1             package Net::Async::WebSearch::Provider::SearxNG;
2             our $VERSION = '0.002';
3             # ABSTRACT: SearxNG/Searx JSON endpoint provider
4 1     1   959 use strict;
  1         2  
  1         27  
5 1     1   4 use warnings;
  1         1  
  1         36  
6 1     1   4 use parent 'Net::Async::WebSearch::Provider';
  1         1  
  1         5  
7              
8 1     1   90 use Carp qw( croak );
  1         1  
  1         37  
9 1     1   3 use Future;
  1         1  
  1         46  
10 1     1   4 use JSON::MaybeXS qw( decode_json );
  1         1  
  1         30  
11 1     1   10 use URI;
  1         2  
  1         15  
12 1     1   3 use HTTP::Request::Common qw( GET );
  1         1  
  1         33  
13 1     1   3 use Net::Async::WebSearch::Result;
  1         2  
  1         508  
14              
15             sub _init {
16 0     0     my ( $self ) = @_;
17 0 0         croak "SearxNG provider requires 'endpoint'" unless $self->{endpoint};
18 0           $self->{endpoint} =~ s{/+$}{};
19 0   0       $self->{name} ||= 'searxng';
20             }
21              
22 0     0 1   sub endpoint { $_[0]->{endpoint} }
23 0     0 1   sub api_key { $_[0]->{api_key} }
24              
25             sub search {
26 0     0 1   my ( $self, $http, $query, $opts ) = @_;
27 0   0       $opts ||= {};
28 0   0       my $limit = $opts->{limit} || 10;
29              
30 0           my $uri = URI->new( $self->endpoint . '/search' );
31 0           my %q = (
32             q => $query,
33             format => 'json',
34             );
35 0 0         $q{language} = $opts->{language} if defined $opts->{language};
36 0 0         $q{safesearch} = $opts->{safesearch} if defined $opts->{safesearch};
37 0 0         $q{categories} = $opts->{categories} if defined $opts->{categories};
38 0 0         $q{engines} = $opts->{engines} if defined $opts->{engines};
39 0 0         $q{pageno} = $opts->{pageno} if defined $opts->{pageno};
40 0           $uri->query_form(%q);
41              
42 0           my $req = GET( $uri->as_string );
43 0           $req->header( 'User-Agent' => $self->user_agent_string );
44 0           $req->header( 'Accept' => 'application/json' );
45 0 0         $req->header( 'Authorization' => 'Bearer ' . $self->api_key ) if defined $self->api_key;
46              
47             return $http->do_request( request => $req )->then(sub {
48 0     0     my ( $resp ) = @_;
49 0 0         unless ( $resp->is_success ) {
50 0           return Future->fail(
51             $self->name.": HTTP ".$resp->status_line, 'websearch', $self->name,
52             );
53             }
54 0           my $data = eval { decode_json( $resp->decoded_content ) };
  0            
55 0 0         if ( my $e = $@ ) {
56 0           return Future->fail( $self->name.": invalid JSON: $e", 'websearch', $self->name );
57             }
58 0           my @out;
59 0           my $rank = 0;
60 0 0         for my $r ( @{ $data->{results} || [] } ) {
  0            
61 0           $rank++;
62             push @out, Net::Async::WebSearch::Result->new(
63             url => $r->{url},
64             title => $r->{title},
65             snippet => $r->{content},
66             provider => $self->name,
67             rank => $rank,
68             published_at => $r->{publishedDate},
69             raw => $r,
70             extra => {
71             ( defined $r->{engine} ? ( engine => $r->{engine} ) : () ),
72             ( defined $r->{category} ? ( category => $r->{category} ) : () ),
73 0 0         ( defined $r->{thumbnail} ? ( thumbnail => $r->{thumbnail} ) : () ),
    0          
    0          
74             },
75             );
76 0 0         last if $rank >= $limit;
77             }
78 0           return Future->done(\@out);
79 0           });
80             }
81              
82             1;
83              
84             __END__