Replace HTTP::Tiny with Mojo::UserAgent and Mojo::UserAgent::Cached

This commit is contained in:
eleksir
2021-04-05 00:56:27 +03:00
parent b8fb89358e
commit 57dee8b168
9 changed files with 205 additions and 199 deletions

View File

@@ -1,5 +1,8 @@
requires 'Carp';
requires 'CHI';
requires 'CHI::Driver::BerkeleyDB';
requires 'Cwd::utf8';
requires 'DateTime';
requires 'DB_File';
requires 'SQLite_File';
requires 'Digest::HMAC_SHA1';
@@ -10,7 +13,6 @@ requires 'File::Basename';
requires 'File::Path';
requires 'Hailo';
requires 'HTML::TokeParser';
requires 'HTTP::Tiny';
requires 'IO::Socket::SSL';
requires 'JSON';
requires 'JSON::XS';
@@ -23,6 +25,7 @@ requires 'Math::Random::Secure';
requires 'Mojo::Base';
requires 'Mojo::IOLoop';
requires 'Mojo::UserAgent';
requires 'Mojo::UserAgent::Cached';
requires 'Text::Fuzzy';
requires 'URI::Encode::XS';
requires 'URI::URL';

View File

@@ -7,8 +7,8 @@ use utf8;
use open qw (:std :utf8);
use English qw ( -no_match_vars );
use Carp qw (cluck);
use HTTP::Tiny;
use HTML::TokeParser;
use Mojo::UserAgent;
use version; our $VERSION = qw (1.0);
use Exporter qw (import);
@@ -19,18 +19,18 @@ sub buni {
my $ret = 'Нету Buni';
for (1..3) {
my $http = HTTP::Tiny->new (timeout => 3);
$r = $http->get ('http://www.bunicomic.com/?random&nocache=1');
my $ua = Mojo::UserAgent->new->connect_timeout (3);
$r = $ua->get ('http://www.bunicomic.com/?random&nocache=1')->result;
if ($r->{success}) {
if ($r->is_success) {
last;
}
sleep 2;
}
if ($r->{success}) {
my $p = HTML::TokeParser->new(\$r->{content});
if ($r->is_success) {
my $p = HTML::TokeParser->new(\$r->body);
my @a;
# additional {} required in order "last" to work properly :)
@@ -47,7 +47,7 @@ sub buni {
} while ($#{$a[0]} > 1);
}
} else {
cluck sprintf 'Server return status %s with message: %s', $r->{status}, $r->{reason};
cluck sprintf 'Server return status %s with message: %s', $r->code, $r->message;
}
return $ret;

View File

@@ -5,11 +5,16 @@ use strict;
use warnings;
use utf8;
use open qw (:std :utf8);
use CHI;
use CHI::Driver::BerkeleyDB;
use DateTime;
use English qw ( -no_match_vars );
use Encode;
use Carp qw (cluck);
use HTTP::Tiny;
use HTML::TokeParser;
use Mojo::Log;
use Mojo::UserAgent::Cached;
use POSIX qw (strftime);
use version; our $VERSION = qw (1.0);
use Exporter qw (import);
@@ -23,19 +28,56 @@ sub drink {
my ($dayNum, $monthNum) = (localtime ())[3, 4];
my $url = sprintf 'https://kakoysegodnyaprazdnik.ru/baza/%s/%s', $MONTH[$monthNum], $dayNum;
for (1..3) {
my $http = HTTP::Tiny->new (timeout => 3);
$r = $http->get ($url, {'Accept-Charset' => 'utf-8', 'Accept-Language' => 'ru-RU'});
# Those POSIX assholes just forgot to add unix timestamps without TZ offset, so...
my ($mday, $mon, $year) = (gmtime ())[3, 4, 5];
my $offset = strftime ('%z', gmtime ());
my $offsetMinutes = (substr $offset, -2) * 60;
my $offsetHours = (substr $offset, 1, 2) * 60 * 60;
my $offsetSign;
if ($r->{success}) {
if ((substr $offset, 0, 1) eq '+') {
$offsetSign = 1;
}
my $expirationDate = DateTime->new (
year => $year + 1900,
month => $mon + 1,
day => $mday,
hour => 0,
minute => 0,
second => 0
)->add (days => 1)->strftime ('%s');
if ((substr $offset, 0, 1) eq '+') {
$expirationDate = $expirationDate - $offsetHours - $offsetMinutes;
} else {
$expirationDate = $expirationDate + $offsetHours + $offsetMinutes;
}
for (1..3) {
my $ua = Mojo::UserAgent::Cached->new->connect_timeout (3);
$ua->cache_agent(
CHI->new (
driver => 'BerkeleyDB',
root_dir => 'data/cache',
namespace => __PACKAGE__,
expires_at => $expirationDate,
expires_on_backend => 1,
)
);
# just to make Mojo::UserAgent::Cached happy
$ua->logger (Mojo::Log->new (path => '/dev/null', level => 'error'));
$r = $ua->get ($url => {'Accept-Language' => 'ru-RU', 'Accept-Charset' => 'utf-8'})->result;
if ($r->is_success) {
last;
}
sleep 2;
}
if ($r->{success}) {
my $p = HTML::TokeParser->new(\$r->{content});
if ($r->is_success) {
my $p = HTML::TokeParser->new(\$r->body);
my @a;
my @holyday;
@@ -58,7 +100,7 @@ sub drink {
$ret = join "\n", @holyday;
}
} else {
cluck sprintf 'Server return status %s with message: %s', $r->{status}, $r->{reason};
cluck sprintf 'Server return status %s with message: %s', $r->code, $r->message;
}
return $ret;

View File

@@ -9,10 +9,9 @@ use English qw ( -no_match_vars );
use Carp qw (cluck);
use Digest::HMAC_SHA1 qw (hmac_sha1);
use File::Path qw (make_path);
use JSON::XS;
use HTTP::Tiny;
use Math::Random::Secure qw (irand);
use MIME::Base64;
use Mojo::UserAgent;
use SQLite_File;
use URI::Encode::XS qw (uri_encode);
@@ -120,15 +119,15 @@ sub flickrRequestToken {
uri_encode ($flickr_callback_url)
);
my $http = HTTP::Tiny->new (timeout => 5);
my $r = $http->get ($url);
my $ua = Mojo::UserAgent->new->connect_timeout (5);
my $r = $ua->get ($url)->result;
my %params;
if ($r->{success}) {
if ($r->is_success) {
# they ignore format=json, so...
%params = map {split /=/} split /&/, $r->{content};
%params = map {split /=/} split /&/, $r->body;
} else {
say "Something bad returns from flickr api: $r->{status} $r->{content}"; ## no critic (InputOutput::RequireCheckedSyscalls)
say "Something bad returns from flickr api: $r->code $r->message"; ## no critic (InputOutput::RequireCheckedSyscalls)
}
return %params;
@@ -161,15 +160,15 @@ sub flickrAccessToken {
uri_encode ($oauth_signature)
);
my $http = HTTP::Tiny->new (timeout => 5);
my $r = $http->get ($url);
my $ua = Mojo::UserAgent->new->connect_timeout (5);
my $r = $ua->get ($url)->result;
my %params;
if ($r->{success}) {
if ($r->is_success) {
# they ignore format=json
%params = map {split /=/} split /&/, $r->{content};
%params = map {split /=/} split /&/, $r->body;
} else {
say "Something bad returns from flickr api: $r->{status} $r->{content}"; ## no critic (InputOutput::RequireCheckedSyscalls)
say "Something bad returns from flickr api: $r->code $r->message"; ## no critic (InputOutput::RequireCheckedSyscalls)
}
return %params;
@@ -183,13 +182,13 @@ sub flickrAuthorization {
$flickr_request_token,
);
my $http = HTTP::Tiny->new (timeout => 5);
my $r = $http->get ($url);
my $ua = Mojo::UserAgent->new->connect_timeout (5);
my $r = $ua->get ($url)->result;
if ($r->{success}) {
return $r->{url};
if ($r->is_success) {
return $r->url;
} else {
say "Something went wrong: $r->{status} $r->{content}"; ## no critic (InputOutput::RequireCheckedSyscalls)
say "Something went wrong: $r->code $r->message"; ## no critic (InputOutput::RequireCheckedSyscalls)
return;
}
}
@@ -224,24 +223,23 @@ sub flickrTestLogin {
uri_encode ($oauth_signature)
);
my $http = HTTP::Tiny->new (timeout => 5);
my $r = $http->get ($url);
my $ua = Mojo::UserAgent->new->connect_timeout (5);
my $r = $ua->get ($url)->result;
if ($r->{success}) {
if ($r->is_success) {
my $response = eval {
my $j = JSON::XS->new->utf8->relaxed;
return $j->decode ($r->{content});
return $r->json;
};
if (defined $response) {
say Dumper $response; ## no critic (InputOutput::RequireCheckedSyscalls)
return 1;
} else {
say "Flickr api returns incorrect json: $r->{content}"; ## no critic (InputOutput::RequireCheckedSyscalls)
say "Flickr api returns incorrect json: $r->message"; ## no critic (InputOutput::RequireCheckedSyscalls)
return 0;
}
} else {
say "HTTP status code not 200: $r->{status}, $r>{contenr}"; ## no critic (InputOutput::RequireCheckedSyscalls)
say "HTTP status code not 200: $r->code, $r->message"; ## no critic (InputOutput::RequireCheckedSyscalls)
return 0;
}
}
@@ -282,13 +280,12 @@ sub flickrSearchByText {
uri_encode ($text)
);
my $http = HTTP::Tiny->new (timeout => 5);
my $r = $http->get ($url);
my $ua = Mojo::UserAgent->new->connect_timeout (5);
my $r = $ua->get ($url)->result;
if ($r->{success}) {
if ($r->is_success) {
my $response = eval {
my $j = JSON::XS->new->utf8->relaxed;
return $j->decode ($r->{content});
return $r->json;
};
if (defined $response) {
@@ -326,31 +323,31 @@ sub flickrSearchByText {
uri_encode ($text)
);
$http = HTTP::Tiny->new (timeout => 5);
$r = $http->get ($url);
$ua = Mojo::UserAgent->new->connect_timeout (5);
$r = $ua->get ($url)->result;
if ($r->{success}) {
if ($r->is_success) {
$response = eval {
my $j = JSON::XS->new->utf8->relaxed;
return $j->decode ($r->{content});
return $r->json;
};
if (defined $response) {
return $response;
} else {
cluck "Flickr api returns incorrect json: $r->{content}";
cluck "Flickr api returns incorrect json: $r->message";
return undef;
}
} else {
cluck "Flickr api returns incorrect json: $r->{content}";
cluck "Flickr api returns incorrect json: $r->message";
return undef;
}
} else {
cluck "Flickr api returns incorrect json: $r->{content}";
cluck "Flickr api returns incorrect json: $r->message";
return undef;
}
} else {
cluck "HTTP status code not 200: $r->{status}, $r->{content}";
cluck "HTTP status code not 200: $r->code, $r->message";
return undef;
}
}
@@ -391,13 +388,12 @@ sub flickrSearchByTags {
uri_encode ($tags)
);
my $http = HTTP::Tiny->new (timeout => 5);
my $r = $http->get ($url);
my $ua = Mojo::UserAgent->new->connect_timeout (5);
my $r = $ua->get ($url)->result;
if ($r->{success}) {
if ($r->is_success) {
my $response = eval {
my $j = JSON::XS->new->utf8->relaxed;
return $j->decode ($r->{content});
return $r->json;
};
if (defined $response) {
@@ -435,31 +431,30 @@ sub flickrSearchByTags {
uri_encode ($tags)
);
$http = HTTP::Tiny->new (timeout => 5);
$r = $http->get ($url);
$ua = Mojo::UserAgent->new->connect_timeout (5);
$r = $ua->get ($url)->result;
if ($r->{success}) {
if ($r->is_success) {
$response = eval {
my $j = JSON::XS->new->utf8->relaxed;
return $j->decode ($r->{content});
return $r->json;
};
if (defined $response) {
return $response;
} else {
cluck "Flickr api returns incorrect json: $r->{content}";
cluck "Flickr api returns incorrect json: $r->message";
return undef;
}
} else {
cluck "Flickr api returns incorrect json: $r->{content}";
cluck "Flickr api returns incorrect json: $r->message";
return undef;
}
} else {
cluck "Flickr api returns incorrect json: $r->{content}";
cluck "Flickr api returns incorrect json: $r->message";
return undef;
}
} else {
cluck "HTTP status code not 200: $r->{status}, $r>{contenr}";
cluck "HTTP status code not 200: $r->code, $r->message";
return undef;
}
}
@@ -484,8 +479,8 @@ sub flickr_init {
my $flickr_request_token_secret = $secret{flickr_request_token_secret};
unless (defined $flickr_request_token || defined $flickr_request_token_secret) {
say "Looks like there is no request token or request token secret in $backingfile";
say "Please remove verifier settings from config.json and run this script again";
say "Looks like there is no request token or request token secret in $backingfile"; ## no critic (InputOutput::RequireCheckedSyscalls)
say 'Please remove verifier settings from config.json and run this script again'; ## no critic (InputOutput::RequireCheckedSyscalls)
untie %secret;
return 0;
}

View File

@@ -8,9 +8,8 @@ use open qw (:std :utf8);
use English qw ( -no_match_vars );
use Carp qw (cluck);
use File::Path qw (make_path);
use JSON::XS;
use HTTP::Tiny;
use Math::Random::Secure qw (irand);
use Mojo::UserAgent;
use SQLite_File;
use conf qw (loadConf);
use flickr qw (flickr_by_tags);
@@ -29,19 +28,19 @@ sub kitty {
my $ret = 'Нету кошечек, все разбежались.';
for (1..3) {
my $http = HTTP::Tiny->new (timeout => 3);
$r = $http->get ('https://api.thecatapi.com/v1/images/search');
my $ua = Mojo::UserAgent->new->connect_timeout (3);
$r = $ua->get ('https://api.thecatapi.com/v1/images/search')->result;
if ($r->{success}) {
if ($r->is_success) {
last;
}
sleep 2;
}
if ($r->{success}) {
if ($r->is_success) {
my $jcat = eval {
decode_json ($r->{content})
return $r->json;
};
unless (defined $jcat) {
@@ -53,7 +52,7 @@ sub kitty {
}
}
} else {
cluck sprintf 'Server return status %s with message: %s', $r->{status}, $r->{reason};
cluck sprintf 'Server return status %s with message: %s', $r->code, $r->message;
}
return $ret;
@@ -64,19 +63,19 @@ sub fox {
my $ret = 'Нету лисичек, все разбежались.';
for (1..3) {
my $http = HTTP::Tiny->new (timeout => 3);
$r = $http->get ('https://randomfox.ca/floof/');
my $ua = Mojo::UserAgent->new->connect_timeout (3);
$r = $ua->get ('https://randomfox.ca/floof/')->result;
if ($r->{success}) {
if ($r->is_success) {
last;
}
sleep 2;
}
if ($r->{success}) {
if ($r->is_success) {
my $jfox = eval {
decode_json ($r->{content})
return $r->json;
};
unless (defined $jfox) {
@@ -88,7 +87,7 @@ sub fox {
}
}
} else {
cluck sprintf 'Server return status %s with message: %s', $r->{status}, $r->{reason};
cluck sprintf 'Server return status %s with message: %s', $r->code, $r->message;
}
return $ret;
@@ -99,19 +98,19 @@ sub oboobs {
my $ret = 'Нету cисичек, все разбежались.';
for (1..3) {
my $http = HTTP::Tiny->new (timeout => 3);
$r = $http->get ('http://api.oboobs.ru/boobs/0/1/random');
my $ua = Mojo::UserAgent->new->connect_timeout (3);
$r = $ua->get ('http://api.oboobs.ru/boobs/0/1/random')->result;
if ($r->{success}) {
if ($r->is_success) {
last;
}
sleep 2;
}
if ($r->{success}) {
if ($r->is_success) {
my $joboobs = eval {
decode_json ($r->{content})
return $r->json;
};
unless (defined $joboobs) {
@@ -123,7 +122,7 @@ sub oboobs {
}
}
} else {
cluck sprintf 'Server return status %s with message: %s', $r->{status}, $r->{reason};
cluck sprintf 'Server return status %s with message: %s', $r->code, $r->message;
}
return $ret;
@@ -134,19 +133,19 @@ sub obutts {
my $ret = 'Нету попок, все разбежались.';
for (1..3) {
my $http = HTTP::Tiny->new (timeout => 3);
$r = $http->get ('http://api.obutts.ru/butts/0/1/random');
my $ua = Mojo::UserAgent->new->connect_timeout (3);
$r = $ua->get ('http://api.obutts.ru/butts/0/1/random')->result;
if ($r->{success}) {
if ($r->is_success) {
last;
}
sleep 2;
}
if ($r->{success}) {
if ($r->is_success) {
my $jobutts = eval {
decode_json ($r->{content})
return $r->json;
};
unless (defined $jobutts) {
@@ -158,7 +157,7 @@ sub obutts {
}
}
} else {
cluck sprintf 'Server return status %s with message: %s', $r->{status}, $r->{reason};
cluck sprintf 'Server return status %s with message: %s', $r->code, $r->message;
}
return $ret;

View File

@@ -8,9 +8,8 @@ use open qw (:std :utf8);
use English qw ( -no_match_vars );
use Carp qw (cluck);
use File::Path qw (make_path);
use JSON::XS;
use HTTP::Tiny;
use Math::Random::Secure qw (irand);
use Mojo::UserAgent;
use SQLite_File;
use conf qw (loadConf);
@@ -30,7 +29,6 @@ sub imgur {
my $refresh_url = 'https://api.imgur.com/oauth2/token';
my $search_url = 'https://api.imgur.com/3/gallery/search/';
my $http = HTTP::Tiny->new (timeout => 5);
# load all tokens from api secrets db
my $backingfile = sprintf '%s/secrets.sqlite', $dir;
@@ -62,20 +60,13 @@ sub imgur {
}
# query api
my $r = $http->get (
$search_url . $tag,
{
headers => {
Authorization => "Bearer $imgur_access_token"
}
}
);
my $ua = Mojo::UserAgent->new->connect_timeout (3);
my $r = $ua->get ($search_url . $tag => {Authorization => "Bearer $imgur_access_token"})->result;
# looks like we need to refresh token
if (($r->{status} == 401) || ($r->{status} == 403)) {
$r = $http->post_form (
$refresh_url,
{
if (($r->code == 401) || ($r->code == 403)) {
$ua->post (
$refresh_url => form {
refresh_token => $imgur_refresh_token,
client_id => $imgur_client_id,
clinent_secret => $imgur_client_secret,
@@ -83,13 +74,13 @@ sub imgur {
}
);
unless ($r->{success}) {
cluck "Unable to refresh imgur token, please re-authorise app! or imgur experiencing api outage: $r->{status} $r->{content}";
unless ($r->is_success) {
cluck "Unable to refresh imgur token, please re-authorise app! or imgur experiencing api outage: $r->code $r->message";
untie %secret;
return undef;
}
my $refresh = eval { decode_json $r->{content} };
my $refresh = eval { return $r->json; };
if (defined $refresh) {
$imgur_refresh_token = $refresh->{refresh_token};
@@ -103,20 +94,13 @@ sub imgur {
}
# query api again
$r = $http->get (
$search_url . $tag,
{
headers => {
Authorization => "Bearer $imgur_access_token"
}
}
);
$r = $ua->get ($search_url . $tag => {Authorization => "Bearer $imgur_access_token"})->result;
}
untie %secret;
if ($r->{success}) {
my $searchResult = eval { decode_json ($r->{content}) };
if ($r->is_success) {
my $searchResult = eval { return $r->json; };
my @urls;
if (defined $searchResult) {
@@ -148,7 +132,7 @@ sub imgur {
return undef;
}
} else {
cluck "Unable to get results from imgur api: $r->{content}";
cluck "Unable to get results from imgur api: $r->message";
return undef;
}
} else {
@@ -156,7 +140,7 @@ sub imgur {
return undef;
}
} else {
cluck "Unable to get results from imgur api: $r->{status}, $r->{content}";
cluck "Unable to get results from imgur api: $r->code, $r->message";
return undef;
}
}

View File

@@ -7,9 +7,9 @@ use utf8;
use open qw (:std :utf8);
use English qw ( -no_match_vars );
use Carp qw (cluck);
use HTTP::Tiny;
use HTML::TokeParser;
use Math::Random::Secure qw (irand);
use Mojo::UserAgent;
use version; our $VERSION = qw (1.0);
use Exporter qw (import);
@@ -21,18 +21,18 @@ sub monkeyuser {
my @link;
for (1..3) {
my $http = HTTP::Tiny->new (timeout => 3);
$r = $http->get ('https://www.monkeyuser.com/toc/');
my $ua = Mojo::UserAgent->new->connect_timeout (3);
$r = $ua->get ('https://www.monkeyuser.com/toc/')->result;
if ($r->{success}) {
if ($r->is_success) {
last;
}
sleep 2;
}
if ($r->{success}) {
my $p = HTML::TokeParser->new(\$r->{content});
if ($r->is_success) {
my $p = HTML::TokeParser->new(\$r->body);
my @a;
do {

View File

@@ -7,11 +7,13 @@ use utf8;
use open qw (:std :utf8);
use English qw ( -no_match_vars );
use Carp qw (carp cluck);
use CHI;
use CHI::Driver::BerkeleyDB;
use DB_File;
use Digest::MD5 qw (md5_base64);
use File::Path qw (make_path);
use HTTP::Tiny;
use JSON::XS;
use Mojo::Log;
use Mojo::UserAgent::Cached;
use conf qw (loadConf);
use util qw (trim urlencode);
@@ -71,77 +73,53 @@ sub weather {
sub __weather {
my $city = shift;
$city = urlencode $city;
my $id = md5_base64 $city;
my $appid = $c->{openweathermap}->{appid};
my $cachedir = $c->{openweathermap}->{cachedir};
my $cachetimefile = $cachedir . '/openweathermap.Id-Timestamp.db';
my $cachedatafile = $cachedir . '/openweathermap.Id-Data.db';
my $now = time ();
my $fc;
my $w;
unless (-d $cachedir) {
make_path ($cachedir) || do {
cluck "[ERROR] Unable to create $cachedir: $OS_ERROR";
return;
my $r;
# try 3 times and giveup
for (1..3) {
my $ua = Mojo::UserAgent::Cached->new;
$ua->local_dir ($cachedir);
$ua->cache_agent(
CHI->new (
driver => 'BerkeleyDB',
root_dir => $cachedir,
namespace => __PACKAGE__,
expires_in => '3 hours',
expires_on_backend => 1,
)
);
# just to make Mojo::UserAgent::Cached happy
$ua->logger (Mojo::Log->new (path => '/dev/null', level => 'error'));
$r = $ua->get (sprintf ('http://api.openweathermap.org/data/2.5/weather?q=%s&lang=ru&APPID=%s', $city, $appid))->result;
if ($r->is_success) {
last;
}
sleep 2;
}
# all 3 times can give error, so check it here
if ($r->is_success) {
$fc = eval {
return $r->json;
};
}
# attach to cache data
tie my %cachetime, 'DB_File', $cachetimefile or do {
carp "[ERROR] Something nasty happen when cachetime ties to its data: $OS_ERROR";
return undef;
};
tie my %cachedata, 'DB_File', $cachedatafile or do {
carp "[ERROR] Something nasty happen when cachedata ties to its data: $OS_ERROR";
return undef;
};
# lookup cache
if (defined ($cachetime{$id}) && ($now - $cachetime{$id}) < 10800) {
$fc = decode_json $cachedata{$id};
} else {
my $r;
# try 3 times and giveup
for (1..3) {
my $http = HTTP::Tiny->new (timeout => 3);
$r = $http->get (sprintf ('http://api.openweathermap.org/data/2.5/weather?q=%s&lang=ru&APPID=%s', $city, $appid));
if ($r->{success}) {
last;
}
sleep 2;
}
# all 3 times can give error, so check it here
if ($r->{success}) {
$fc = eval {
decode_json $r->{content};
};
if ($EVAL_ERROR) {
cluck "[WARN] openweathermap returns corrupted json: $EVAL_ERROR";
untie %cachetime;
untie %cachedata;
return undef;
};
$cachetime{$id} = $now;
$cachedata{$id} = encode_json $fc;
} else {
cluck sprintf 'Server return status %s with message: %s', $r->{status}, $r->{reason};
untie %cachetime;
untie %cachedata;
unless ($fc) {
cluck "[WARN] openweathermap returns corrupted json: $EVAL_ERROR";
return undef;
}
};
} else {
cluck sprintf 'Server return status %s with message: %s', $r->code, $r->message;
return undef;
}
untie %cachetime;
untie %cachedata;
# TODO: check all of this for existence
$w->{'name'} = $fc->{name};
$w->{'state'} = $fc->{state};

View File

@@ -5,18 +5,23 @@ use strict;
use warnings;
use utf8;
use open qw (:std :utf8);
use HTTP::Tiny;
use Mojo::UserAgent;
use version; our $VERSION = qw (1.0);
use Exporter qw (import);
our @EXPORT_OK = qw (xkcd);
sub xkcd {
my $http = HTTP::Tiny->new (timeout => 5, max_redirect => 0);
my $r = $http->get ('https://xkcd.ru/random/');
my $ua = Mojo::UserAgent->new->connect_timeout (5)->max_redirects (0);
my $r = $ua->get ('https://xkcd.ru/random/')->result;
if (defined $r->{headers} && defined $r->{headers}->{location} && $r->{headers}->{location} ne '') {
return sprintf '[xkcd.ru](https://xkcd.ru/i/%s_v1.png)', substr ($r->{headers}->{location}, 1, -1);
if (
defined $r->content &&
defined $r->content->headers &&
defined $r->content->headers->location &&
$r->content->headers->location ne ''
) {
return sprintf '[xkcd.ru](https://xkcd.ru/i/%s_v1.png)', substr ($r->content->headers->location, 1, -1);
}
return 'Комикс-стрип нарисовать не так-то просто :(';