PageRenderTime 57ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/WWW/DuckDuckGo.pm

https://github.com/duckduckgo/p5-www-duckduckgo
Perl | 194 lines | 175 code | 17 blank | 2 comment | 7 complexity | f18f35ebcc498d9e948773317421c396 MD5 | raw file
  1. package WWW::DuckDuckGo;
  2. # ABSTRACT: Access to the DuckDuckGo APIs
  3. use Moo;
  4. use LWP::UserAgent;
  5. use HTTP::Request;
  6. use WWW::DuckDuckGo::ZeroClickInfo;
  7. use JSON;
  8. use URI;
  9. use URI::QueryParam;
  10. our $VERSION ||= '0.0development';
  11. has _duckduckgo_api_url => (
  12. is => 'ro',
  13. lazy => 1,
  14. default => sub { 'http://api.duckduckgo.com/' },
  15. );
  16. has _duckduckgo_api_url_secure => (
  17. is => 'ro',
  18. lazy => 1,
  19. default => sub { 'https://api.duckduckgo.com/' },
  20. );
  21. has _zeroclickinfo_class => (
  22. is => 'ro',
  23. lazy => 1,
  24. default => sub { 'WWW::DuckDuckGo::ZeroClickInfo' },
  25. );
  26. has _http_agent => (
  27. is => 'ro',
  28. lazy => 1,
  29. default => sub {
  30. my $self = shift;
  31. my $ua = LWP::UserAgent->new;
  32. $ua->agent($self->http_agent_name);
  33. return $ua;
  34. },
  35. );
  36. has http_agent_name => (
  37. is => 'ro',
  38. lazy => 1,
  39. default => sub { __PACKAGE__.'/'.$VERSION },
  40. );
  41. has forcesecure => (
  42. is => 'ro',
  43. default => sub { 0 },
  44. );
  45. has safeoff => (
  46. is => 'ro',
  47. default => sub { 0 },
  48. );
  49. has html => (
  50. is => 'ro',
  51. default => sub { 0 },
  52. );
  53. # HashRef of extra params
  54. has params => (
  55. is => 'ro',
  56. default => sub { {} },
  57. );
  58. sub zci { shift->zeroclickinfo(@_) }
  59. sub _zeroclickinfo_request_base {
  60. my ( $self, $for_uri, @query_fields ) = @_;
  61. my $query = join(' ',@query_fields);
  62. my $uri = URI->new($for_uri);
  63. my %params = %{$self->params};
  64. $uri->query_param( q => $query );
  65. $uri->query_param( o => 'json' );
  66. $uri->query_param( kp => -1 ) if $self->safeoff;
  67. $uri->query_param( no_redirect => 1 );
  68. $self->html ?
  69. $uri->query_param( no_html => 0 ) :
  70. $uri->query_param( no_html => 1 );
  71. $uri->query_param($_ => $params{$_}) for keys %params;
  72. return HTTP::Request->new(GET => $uri->as_string);
  73. }
  74. sub zeroclickinfo_request_secure {
  75. my ( $self, @query_fields ) = @_;
  76. return if !@query_fields;
  77. return $self->_zeroclickinfo_request_base($self->_duckduckgo_api_url_secure,@query_fields);
  78. }
  79. sub zeroclickinfo_request {
  80. my ( $self, @query_fields ) = @_;
  81. return if !@query_fields;
  82. return $self->_zeroclickinfo_request_base($self->_duckduckgo_api_url,@query_fields);
  83. }
  84. sub zeroclickinfo {
  85. my ( $self, @query_fields ) = @_;
  86. return if !@query_fields;
  87. my $query = join(' ',@query_fields);
  88. my $res;
  89. eval {
  90. $res = $self->_http_agent->request($self->zeroclickinfo_request_secure(@query_fields));
  91. };
  92. if (!$self->forcesecure and ( $@ or !$res or !$res->is_success ) ) {
  93. warn __PACKAGE__." HTTP request failed: ".$res->status_line if ($res and !$res->is_success);
  94. warn __PACKAGE__." Can't access ".$self->_duckduckgo_api_url_secure." falling back to: ".$self->_duckduckgo_api_url;
  95. $res = $self->_http_agent->request($self->zeroclickinfo_request(@query_fields));
  96. }
  97. return $self->zeroclickinfo_by_response($res);
  98. }
  99. sub zeroclickinfo_by_response {
  100. my ( $self, $response ) = @_;
  101. if ($response->is_success) {
  102. my $result = decode_json($response->content);
  103. return $self->_zeroclickinfo_class->by($result);
  104. } else {
  105. die __PACKAGE__.' HTTP request failed: '.$response->status_line, "\n";
  106. }
  107. }
  108. 1;
  109. =encoding utf8
  110. =head1 SYNOPSIS
  111. use WWW::DuckDuckGo;
  112. my $duck = WWW::DuckDuckGo->new;
  113. # request the Zero Click Info, you can also use ..->zci('duck duck go')
  114. my $zeroclickinfo = $duck->zeroclickinfo('duck duck go');
  115. # request the Zero Click Info of "duck duck go more stuff"
  116. my $other_zeroclickinfo = $duck->zeroclickinfo('duck duck go','more stuff');
  117. =head1 DESCRIPTION
  118. This distribution gives you an easy access to the DuckDuckGo Zero Click Info API. It tries to connect via https first and falls back to http if there is a failure.
  119. =head1 ATTRIBUTES
  120. =attr forcesecure
  121. Set to true will force the client to use https, so it will not fallback to http on failure.
  122. =attr http_agent_name
  123. Set the http agent name which the webserver gets. Defaults to WWW::DuckDuckGo
  124. =attr safeoff
  125. Set to true to disable safesearch.
  126. =attr html
  127. Allow HTML in output. This is the default in DuckDuckGo, but not default here to maintain backwards compatibility.
  128. =attr params
  129. A HashRef of extra GET params to pass with the query (documented on https://api.duckduckgo.com/)
  130. =head1 METHODS
  131. =method $obj->zeroclickinfo
  132. Arguments: @query_fields
  133. Return value: L<WWW::DuckDuckGo::ZeroClickInfo>
  134. Returns the L<WWW::DuckDuckGo::ZeroClickInfo> of the query specified by the parameters. If you give several parameters they will get joined with an empty space.
  135. =head1 SUPPORT
  136. IRC
  137. Join #duckduckgo on irc.freenode.net.
  138. Repository
  139. http://github.com/duckduckgo/p5-www-duckduckgo
  140. Pull request and additional contributors are welcome
  141. Issue Tracker
  142. http://github.com/duckduckgo/p5-www-duckduckgo/issues