Implemented !monkeyuser, !drink, !праздник, !owl, !сова, !bunny, !rabbit, !кролик commands
This commit is contained in:
29
bin/flickr_init.pl
Normal file
29
bin/flickr_init.pl
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
|
||||||
|
use 5.018;
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use utf8;
|
||||||
|
use open qw (:std :utf8);
|
||||||
|
use English qw ( -no_match_vars );
|
||||||
|
use version; our $VERSION = qw (1.0);
|
||||||
|
|
||||||
|
my $workdir;
|
||||||
|
|
||||||
|
# before we run, change working dir
|
||||||
|
BEGIN {
|
||||||
|
use Cwd qw (chdir abs_path);
|
||||||
|
my @CWD = split /\//xms, abs_path ($PROGRAM_NAME);
|
||||||
|
if ($#CWD > 1) { $#CWD = $#CWD - 2; }
|
||||||
|
$workdir = join '/', @CWD;
|
||||||
|
chdir $workdir;
|
||||||
|
}
|
||||||
|
|
||||||
|
use lib ("$workdir/lib", "$workdir/vendor_perl", "$workdir/vendor_perl/lib/perl5");
|
||||||
|
use flickr qw (flickr_init);
|
||||||
|
|
||||||
|
if (flickr_init ()) {
|
||||||
|
exit 0;
|
||||||
|
} else {
|
||||||
|
exit 1;
|
||||||
|
}
|
||||||
@@ -15,6 +15,14 @@
|
|||||||
"csign": "!"
|
"csign": "!"
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"image": {
|
||||||
|
"dir" : "data/image",
|
||||||
|
"flickr" : {
|
||||||
|
"consumer_key" : "md5-like_hash",
|
||||||
|
"consumer_secret" : "some_hash-like_string",
|
||||||
|
"verifier": "some_hash-like_string"
|
||||||
|
}
|
||||||
|
},
|
||||||
"openweathermap" : {
|
"openweathermap" : {
|
||||||
"cachetime": "data/cache/openweathermap.Id-Timestamp.db",
|
"cachetime": "data/cache/openweathermap.Id-Timestamp.db",
|
||||||
"cachedata": "data/cache/openweathermap.Id-Data.db",
|
"cachedata": "data/cache/openweathermap.Id-Data.db",
|
||||||
|
|||||||
@@ -13,13 +13,16 @@ use Math::Random::Secure qw (irand);
|
|||||||
use archeologist qw (dig);
|
use archeologist qw (dig);
|
||||||
use buni qw (buni);
|
use buni qw (buni);
|
||||||
use conf qw (loadConf);
|
use conf qw (loadConf);
|
||||||
|
use drink qw (drink);
|
||||||
use fisher qw (fish);
|
use fisher qw (fish);
|
||||||
use fortune qw (fortune);
|
use fortune qw (fortune);
|
||||||
use fox qw (fox);
|
use fox qw (fox);
|
||||||
use friday qw (friday);
|
use friday qw (friday);
|
||||||
|
use image wq (rabbit owl);
|
||||||
use karma qw (karmaGet);
|
use karma qw (karmaGet);
|
||||||
use kitty qw (kitty);
|
use kitty qw (kitty);
|
||||||
use lat qw (latAnswer);
|
use lat qw (latAnswer);
|
||||||
|
use monkeyuser qw (monkeyuser);
|
||||||
use util qw (trim utf2sha1);
|
use util qw (trim utf2sha1);
|
||||||
use weather qw (weather);
|
use weather qw (weather);
|
||||||
use xkcd qw (xkcd);
|
use xkcd qw (xkcd);
|
||||||
@@ -185,8 +188,11 @@ sub command {
|
|||||||
|
|
||||||
${csign}help | ${csign}помощь - это сообщение
|
${csign}help | ${csign}помощь - это сообщение
|
||||||
${csign}buni - комикс-стрип hapi buni
|
${csign}buni - комикс-стрип hapi buni
|
||||||
|
${csign}bunny - кролик
|
||||||
|
${csign}rabbit | ${csign}кролик - кролик
|
||||||
${csign}cat | ${csign}кис - кошечка
|
${csign}cat | ${csign}кис - кошечка
|
||||||
${csign}dig | ${csign}копать - заняться археологией
|
${csign}dig | ${csign}копать - заняться археологией
|
||||||
|
${csign}drink | ${csign}праздник - какой сегодня праздник?
|
||||||
${csign}fish | ${csign}fisher - порыбачить
|
${csign}fish | ${csign}fisher - порыбачить
|
||||||
${csign}рыба | ${csign}рыбка | ${csign}рыбалка - порыбачить
|
${csign}рыба | ${csign}рыбка | ${csign}рыбалка - порыбачить
|
||||||
${csign}f | ${csign}ф - рандомная фраза из сборника цитат fortune_mod
|
${csign}f | ${csign}ф - рандомная фраза из сборника цитат fortune_mod
|
||||||
@@ -197,6 +203,8 @@ ${csign}karma фраза - посмотреть карму фраз
|
|||||||
${csign}карма фраза - посмотреть карму фразы
|
${csign}карма фраза - посмотреть карму фразы
|
||||||
фраза++ | фраза-- - повысить или понизить карму фразы
|
фраза++ | фраза-- - повысить или понизить карму фразы
|
||||||
${csign}lat | ${csign}лат - сгенерировать фразу из крылатого латинского выражения
|
${csign}lat | ${csign}лат - сгенерировать фразу из крылатого латинского выражения
|
||||||
|
${csign}monkeyuser - комикс-стрип MonkeyUser
|
||||||
|
${csign}owl | ${csign}сова - сова
|
||||||
${csign}ping | ${csign}пинг - попинговать бота
|
${csign}ping | ${csign}пинг - попинговать бота
|
||||||
${csign}some_brew - выдать соответствующий напиток, бармен может налить rum, ром, vodka, водку, beer, пиво, tequila, текила, whisky, виски, absinthe, абсент
|
${csign}some_brew - выдать соответствующий напиток, бармен может налить rum, ром, vodka, водку, beer, пиво, tequila, текила, whisky, виски, absinthe, абсент
|
||||||
${csign}ver | ${csign}version - написать что-то про версию ПО
|
${csign}ver | ${csign}version - написать что-то про версию ПО
|
||||||
@@ -219,6 +227,14 @@ EOL
|
|||||||
$reply = buni ();
|
$reply = buni ();
|
||||||
} elsif (substr ($text, 1) eq 'xkcd') {
|
} elsif (substr ($text, 1) eq 'xkcd') {
|
||||||
$reply = xkcd ();
|
$reply = xkcd ();
|
||||||
|
} elsif (substr ($text, 1) eq 'monkeyuser') {
|
||||||
|
$reply = monkeyuser ();
|
||||||
|
} elsif (substr ($text, 1) eq 'drink' || substr ($text, 1) eq 'праздник') {
|
||||||
|
$reply = drink ();
|
||||||
|
} elsif (substr ($text, 1) eq 'bunny' || substr ($text, 1) eq 'rabbit' || substr ($text, 1) eq 'кролик') {
|
||||||
|
$reply = rabbit ();
|
||||||
|
} elsif (substr ($text, 1) eq 'owl' || substr ($text, 1) eq 'сова') {
|
||||||
|
$reply = owl ();
|
||||||
} elsif ((length ($text) >= 6 && (substr ($text, 1, 6) eq 'karma ' || substr ($text, 1, 6) eq 'карма ')) || substr ($text, 1) eq 'karma' || substr ($text, 1) eq 'карма') {
|
} elsif ((length ($text) >= 6 && (substr ($text, 1, 6) eq 'karma ' || substr ($text, 1, 6) eq 'карма ')) || substr ($text, 1) eq 'karma' || substr ($text, 1) eq 'карма') {
|
||||||
my $mytext = '';
|
my $mytext = '';
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ sub buni {
|
|||||||
{
|
{
|
||||||
do {
|
do {
|
||||||
$#a = -1;
|
$#a = -1;
|
||||||
@a = $p->get_tag("meta");
|
@a = $p->get_tag('meta'); ## no critic (Variables::RequireLocalizedPunctuationVars)
|
||||||
|
|
||||||
if (defined $a[0][1]->{property} && $a[0][1]->{property} eq 'og:image') {
|
if (defined $a[0][1]->{property} && $a[0][1]->{property} eq 'og:image') {
|
||||||
$ret = $a[0][1]->{content};
|
$ret = $a[0][1]->{content};
|
||||||
|
|||||||
116
lib/drink.pm
Normal file
116
lib/drink.pm
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
package drink;
|
||||||
|
|
||||||
|
use 5.018;
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use utf8;
|
||||||
|
use open qw (:std :utf8);
|
||||||
|
use English qw ( -no_match_vars );
|
||||||
|
use Encode;
|
||||||
|
use Carp qw (cluck);
|
||||||
|
use HTTP::Tiny;
|
||||||
|
use HTML::TokeParser;
|
||||||
|
|
||||||
|
use version; our $VERSION = qw (1.0);
|
||||||
|
use Exporter qw (import);
|
||||||
|
our @EXPORT_OK = qw (drink drink2);
|
||||||
|
|
||||||
|
my @MONTH = qw (yanvar fevral mart aprel may iyun iyul avgust sentyabr oktyabr noyabr dekabr);
|
||||||
|
|
||||||
|
sub drink {
|
||||||
|
my $r;
|
||||||
|
my $ret = 'Не знаю праздников - вджобываю весь день на шахтах, как проклятая.';
|
||||||
|
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'});
|
||||||
|
|
||||||
|
if ($r->{success}) {
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
|
||||||
|
sleep 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($r->{success}) {
|
||||||
|
my $p = HTML::TokeParser->new(\$r->{content});
|
||||||
|
my @a;
|
||||||
|
my @holyday;
|
||||||
|
|
||||||
|
do {
|
||||||
|
$#a = -1;
|
||||||
|
@a = $p->get_tag('span'); ## no critic (Variables::RequireLocalizedPunctuationVars)
|
||||||
|
|
||||||
|
if ($#{$a[0]} > 2 && defined $a[0][1]->{itemprop} && $a[0][1]->{itemprop} eq 'text') {
|
||||||
|
push @holyday,'* ' . decode ('UTF-8', $p->get_trimmed_text ('/span'));
|
||||||
|
}
|
||||||
|
|
||||||
|
} while ($#{$a[0]} > 1);
|
||||||
|
|
||||||
|
if ($#holyday > 0) {
|
||||||
|
# cut off something weird, definely not a "holyday"
|
||||||
|
$#holyday = $#holyday - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($#holyday > 0) {
|
||||||
|
$ret = join "\n", @holyday;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cluck sprintf 'Server return status %s with message: %s', $r->{status}, $r->{reason};
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub drink2 {
|
||||||
|
my $r;
|
||||||
|
my $ret = 'Не знаю праздников - вджобываю весь день на шахтах, как проклятая.';
|
||||||
|
my ($dayNum, $monthNum) = (localtime ())[3, 4];
|
||||||
|
my $url = sprintf 'https://calendareveryday.ru/?id=prazdniki', $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'});
|
||||||
|
|
||||||
|
if ($r->{success}) {
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
|
||||||
|
sleep 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($r->{success}) {
|
||||||
|
my $p = HTML::TokeParser->new(\$r->{content});
|
||||||
|
my @a;
|
||||||
|
my @holyday;
|
||||||
|
|
||||||
|
do {
|
||||||
|
$#a = -1;
|
||||||
|
@a = $p->get_tag('span'); ## no critic (Variables::RequireLocalizedPunctuationVars)
|
||||||
|
|
||||||
|
if ($#{$a[0]} > 2 && defined $a[0][1]->{itemprop} && $a[0][1]->{itemprop} eq 'text') {
|
||||||
|
push @holyday,'* ' . decode ('UTF-8', $p->get_trimmed_text ('/span'));
|
||||||
|
}
|
||||||
|
|
||||||
|
} while ($#{$a[0]} > 1);
|
||||||
|
|
||||||
|
if ($#holyday > 0) {
|
||||||
|
# cut off something weird, definely not a "holyday"
|
||||||
|
$#holyday = $#holyday - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($#holyday > 0) {
|
||||||
|
$ret = join "\n", @holyday;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cluck sprintf 'Server return status %s with message: %s', $r->{status}, $r->{reason};
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
|
|
||||||
|
# vim: set ft=perl noet ai ts=4 sw=4 sts=4:
|
||||||
639
lib/flickr.pm
Normal file
639
lib/flickr.pm
Normal file
@@ -0,0 +1,639 @@
|
|||||||
|
package flickr;
|
||||||
|
|
||||||
|
use 5.018;
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use utf8;
|
||||||
|
use open qw (:std :utf8);
|
||||||
|
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 SQLite_File;
|
||||||
|
use URI::Encode::XS qw (uri_encode);
|
||||||
|
|
||||||
|
use conf qw (loadConf);
|
||||||
|
use util qw (urlencode);
|
||||||
|
|
||||||
|
use Data::Dumper;
|
||||||
|
|
||||||
|
use version; our $VERSION = qw (1.0);
|
||||||
|
use Exporter qw (import);
|
||||||
|
our @EXPORT_OK = qw (flickr_init flickr_by_tags flickr_by_text flickr_test_login);
|
||||||
|
|
||||||
|
my $c = loadConf ();
|
||||||
|
my $dir = $c->{image}->{dir};
|
||||||
|
|
||||||
|
my $flickr_consumer_key = $c->{image}->{flickr}->{consumer_key};
|
||||||
|
my $flickr_consumer_secret = $c->{image}->{flickr}->{consumer_secret};
|
||||||
|
my $flickr_verifier = $c->{image}->{flickr}->{verifier};
|
||||||
|
my $flickr_request_token_url = 'https://www.flickr.com/services/oauth/request_token';
|
||||||
|
my $flickr_authorization_url = 'https://www.flickr.com/services/oauth/authorize';
|
||||||
|
my $flickr_access_token_url = 'https://www.flickr.com/services/oauth/access_token';
|
||||||
|
my $flickr_callback_url = 'http://www.example.com';
|
||||||
|
my $flickr_api_url = 'https://www.flickr.com/services/rest/';
|
||||||
|
|
||||||
|
sub mknonce {
|
||||||
|
# make random number, 8 symbols in length
|
||||||
|
my $nonce = sprintf '%08d', irand (99999999);
|
||||||
|
return $nonce;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub flickerSignReq {
|
||||||
|
my %p = @_;
|
||||||
|
my $string;
|
||||||
|
my $hmac;
|
||||||
|
|
||||||
|
if ($p{type} eq 'request_token') {
|
||||||
|
my @parameters;
|
||||||
|
delete $p{type};
|
||||||
|
push @parameters, 'oauth_signature_method=HMAC-SHA1';
|
||||||
|
push @parameters, 'oauth_version=1.0';
|
||||||
|
push @parameters, sprintf 'oauth_callback=%s', uri_encode ($flickr_callback_url);
|
||||||
|
push @parameters, sprintf 'oauth_consumer_key=%s', $flickr_consumer_key;
|
||||||
|
|
||||||
|
foreach my $param (keys %p) {
|
||||||
|
push @parameters, sprintf ('%s=%s', $param, $p{$param});
|
||||||
|
}
|
||||||
|
|
||||||
|
$string = sprintf 'GET&%s&', uri_encode ($flickr_request_token_url);
|
||||||
|
$string .= uri_encode (join '&', sort (@parameters));
|
||||||
|
# Thanks to twitter api dev portal, they explain this particular case: while we requesting this token
|
||||||
|
# we do not yet know access_token secret, so we just omit it in this signature
|
||||||
|
# https://developer.twitter.com/en/docs/authentication/oauth-1-0a/creating-a-signature
|
||||||
|
$hmac = Digest::HMAC_SHA1->new (sprintf '%s&', uri_encode ($flickr_consumer_secret));
|
||||||
|
} elsif ($p{type} eq 'access_token') {
|
||||||
|
my @parameters;
|
||||||
|
my $flickr_request_token_secret = $p{oauth_token_secret};
|
||||||
|
delete $p{oauth_token_secret};
|
||||||
|
delete $p{type};
|
||||||
|
push @parameters, 'oauth_signature_method=HMAC-SHA1';
|
||||||
|
push @parameters, 'oauth_version=1.0';
|
||||||
|
push @parameters, sprintf 'oauth_consumer_key=%s', $flickr_consumer_key;
|
||||||
|
|
||||||
|
foreach my $param (keys %p) {
|
||||||
|
push @parameters, sprintf ('%s=%s', $param, $p{$param});
|
||||||
|
}
|
||||||
|
|
||||||
|
$string = sprintf 'GET&%s&', uri_encode ($flickr_access_token_url);
|
||||||
|
$string .= uri_encode (join '&', sort (@parameters));
|
||||||
|
$hmac = Digest::HMAC_SHA1->new (sprintf '%s&%s', uri_encode ($flickr_consumer_secret), uri_encode ($flickr_request_token_secret));
|
||||||
|
} elsif ($p{type} eq 'test_login' || $p{type} eq 'search_text' || $p{type} eq 'search_tags') {
|
||||||
|
my @parameters;
|
||||||
|
my $flickr_request_token_secret = $p{oauth_token_secret};
|
||||||
|
delete $p{oauth_token_secret};
|
||||||
|
delete $p{type};
|
||||||
|
|
||||||
|
foreach my $param (keys %p) {
|
||||||
|
push @parameters, sprintf ('%s=%s', $param, $p{$param});
|
||||||
|
}
|
||||||
|
|
||||||
|
$string = sprintf 'GET&%s&', uri_encode ($flickr_api_url);
|
||||||
|
$string .= uri_encode (join '&', sort (@parameters));
|
||||||
|
$hmac = Digest::HMAC_SHA1->new (sprintf '%s&%s', uri_encode ($flickr_consumer_secret), uri_encode ($flickr_request_token_secret));
|
||||||
|
}
|
||||||
|
|
||||||
|
$hmac->add ($string);
|
||||||
|
return encode_base64 ($hmac->digest, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
sub flickrRequestToken {
|
||||||
|
my $oauth_timestamp = time ();
|
||||||
|
my $oauth_nonce = mknonce ();
|
||||||
|
|
||||||
|
my $oauth_signature = flickerSignReq (
|
||||||
|
type => 'request_token',
|
||||||
|
oauth_timestamp => $oauth_timestamp,
|
||||||
|
oauth_nonce => $oauth_nonce
|
||||||
|
);
|
||||||
|
|
||||||
|
my $url = $flickr_request_token_url . sprintf (
|
||||||
|
'?oauth_nonce=%s&oauth_timestamp=%s&oauth_consumer_key=%s&oauth_signature_method=HMAC-SHA1&oauth_version=1.0&&oauth_signature=%s&oauth_callback=%s',
|
||||||
|
$oauth_nonce,
|
||||||
|
$oauth_timestamp,
|
||||||
|
$flickr_consumer_key,
|
||||||
|
uri_encode ($oauth_signature),
|
||||||
|
uri_encode ($flickr_callback_url)
|
||||||
|
);
|
||||||
|
|
||||||
|
my $http = HTTP::Tiny->new (timeout => 5);
|
||||||
|
my $r = $http->get ($url);
|
||||||
|
my %params;
|
||||||
|
|
||||||
|
if ($r->{success}) {
|
||||||
|
# they ignore format=json, so...
|
||||||
|
%params = map {split /=/} split /&/, $r->{content};
|
||||||
|
} else {
|
||||||
|
say "Something bad returns from flickr api: $r->{status} $r->{content}"; ## no critic (InputOutput::RequireCheckedSyscalls)
|
||||||
|
}
|
||||||
|
|
||||||
|
return %params;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub flickrAccessToken {
|
||||||
|
my $flickr_request_token = shift;
|
||||||
|
my $flickr_request_token_secret = shift;
|
||||||
|
my $flickr_verifier = shift; ## no critic (Variables::ProhibitReusedNames)
|
||||||
|
|
||||||
|
my $oauth_timestamp = time ();
|
||||||
|
my $oauth_nonce = mknonce ();
|
||||||
|
|
||||||
|
my $oauth_signature = flickerSignReq (
|
||||||
|
type => 'access_token',
|
||||||
|
oauth_timestamp => $oauth_timestamp,
|
||||||
|
oauth_nonce => $oauth_nonce,
|
||||||
|
oauth_token => $flickr_request_token,
|
||||||
|
oauth_token_secret => $flickr_request_token_secret,
|
||||||
|
oauth_verifier => $flickr_verifier
|
||||||
|
);
|
||||||
|
|
||||||
|
my $url = $flickr_access_token_url . sprintf (
|
||||||
|
'?oauth_nonce=%s&oauth_timestamp=%s&oauth_verifier=%s&oauth_consumer_key=%s&oauth_signature_method=HMAC-SHA1&oauth_version=1.0&oauth_token=%s&oauth_signature=%s',
|
||||||
|
$oauth_nonce,
|
||||||
|
$oauth_timestamp,
|
||||||
|
$flickr_verifier,
|
||||||
|
$flickr_consumer_key,
|
||||||
|
$flickr_request_token,
|
||||||
|
uri_encode ($oauth_signature)
|
||||||
|
);
|
||||||
|
|
||||||
|
my $http = HTTP::Tiny->new (timeout => 5);
|
||||||
|
my $r = $http->get ($url);
|
||||||
|
my %params;
|
||||||
|
|
||||||
|
if ($r->{success}) {
|
||||||
|
# they ignore format=json
|
||||||
|
%params = map {split /=/} split /&/, $r->{content};
|
||||||
|
} else {
|
||||||
|
say "Something bad returns from flickr api: $r->{status} $r->{content}"; ## no critic (InputOutput::RequireCheckedSyscalls)
|
||||||
|
}
|
||||||
|
|
||||||
|
return %params;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub flickrAuthorization {
|
||||||
|
my $flickr_request_token = shift;
|
||||||
|
|
||||||
|
my $url = $flickr_authorization_url . sprintf (
|
||||||
|
'?oauth_token=%s&perms=read',
|
||||||
|
$flickr_request_token,
|
||||||
|
);
|
||||||
|
|
||||||
|
my $http = HTTP::Tiny->new (timeout => 5);
|
||||||
|
my $r = $http->get ($url);
|
||||||
|
|
||||||
|
if ($r->{success}) {
|
||||||
|
return $r->{url};
|
||||||
|
} else {
|
||||||
|
say "Something went wrong: $r->{status} $r->{content}"; ## no critic (InputOutput::RequireCheckedSyscalls)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub flickrTestLogin {
|
||||||
|
my $flickr_access_token = shift;
|
||||||
|
my $flickr_access_token_secret = shift;
|
||||||
|
|
||||||
|
my $oauth_timestamp = time ();
|
||||||
|
my $oauth_nonce = mknonce ();
|
||||||
|
|
||||||
|
my $oauth_signature = flickerSignReq (
|
||||||
|
nojsoncallback => 1,
|
||||||
|
oauth_nonce => $oauth_nonce,
|
||||||
|
format => 'json',
|
||||||
|
oauth_consumer_key => $flickr_consumer_key,
|
||||||
|
oauth_timestamp => $oauth_timestamp,
|
||||||
|
type => 'test_login',
|
||||||
|
method => 'flickr.test.login',
|
||||||
|
oauth_token => $flickr_access_token,
|
||||||
|
oauth_token_secret => $flickr_access_token_secret,
|
||||||
|
oauth_signature_method => 'HMAC-SHA1',
|
||||||
|
oauth_version => '1.0'
|
||||||
|
);
|
||||||
|
|
||||||
|
my $url = $flickr_api_url . sprintf (
|
||||||
|
'?nojsoncallback=1&oauth_nonce=%s&format=json&oauth_consumer_key=%s&oauth_timestamp=%s&oauth_signature_method=HMAC-SHA1&oauth_version=1.0&oauth_token=%s&oauth_signature=%s&method=flickr.test.login',
|
||||||
|
$oauth_nonce,
|
||||||
|
$flickr_consumer_key,
|
||||||
|
$oauth_timestamp,
|
||||||
|
$flickr_access_token,
|
||||||
|
uri_encode ($oauth_signature)
|
||||||
|
);
|
||||||
|
|
||||||
|
my $http = HTTP::Tiny->new (timeout => 5);
|
||||||
|
my $r = $http->get ($url);
|
||||||
|
|
||||||
|
if ($r->{success}) {
|
||||||
|
my $response = eval {
|
||||||
|
my $j = JSON::XS->new->utf8->relaxed;
|
||||||
|
return $j->decode ($r->{content});
|
||||||
|
};
|
||||||
|
|
||||||
|
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)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
say "HTTP status code not 200: $r->{status}, $r>{contenr}"; ## no critic (InputOutput::RequireCheckedSyscalls)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub flickrSearchByText {
|
||||||
|
my $flickr_access_token = shift;
|
||||||
|
my $flickr_access_token_secret = shift;
|
||||||
|
my $text = shift;
|
||||||
|
|
||||||
|
my $oauth_timestamp = time ();
|
||||||
|
my $oauth_nonce = mknonce ();
|
||||||
|
|
||||||
|
my $oauth_signature = flickerSignReq (
|
||||||
|
nojsoncallback => 1,
|
||||||
|
oauth_nonce => $oauth_nonce,
|
||||||
|
format => 'json',
|
||||||
|
oauth_consumer_key => $flickr_consumer_key,
|
||||||
|
oauth_timestamp => $oauth_timestamp,
|
||||||
|
type => 'search_text',
|
||||||
|
content_type => 1,
|
||||||
|
media => 'photos',
|
||||||
|
method => 'flickr.photos.search',
|
||||||
|
text => $text,
|
||||||
|
per_page => 1,
|
||||||
|
oauth_token => $flickr_access_token,
|
||||||
|
oauth_token_secret => $flickr_access_token_secret,
|
||||||
|
oauth_signature_method => 'HMAC-SHA1',
|
||||||
|
oauth_version => '1.0'
|
||||||
|
);
|
||||||
|
|
||||||
|
my $url = $flickr_api_url . sprintf (
|
||||||
|
'?nojsoncallback=1&oauth_nonce=%s&format=json&oauth_consumer_key=%s&oauth_timestamp=%s&oauth_signature_method=HMAC-SHA1&oauth_version=1.0&oauth_token=%s&oauth_signature=%s&method=flickr.photos.search&content_type=1&media=photos&per_page=1&text=%s',
|
||||||
|
$oauth_nonce,
|
||||||
|
$flickr_consumer_key,
|
||||||
|
$oauth_timestamp,
|
||||||
|
$flickr_access_token,
|
||||||
|
uri_encode ($oauth_signature),
|
||||||
|
uri_encode ($text)
|
||||||
|
);
|
||||||
|
|
||||||
|
my $http = HTTP::Tiny->new (timeout => 5);
|
||||||
|
my $r = $http->get ($url);
|
||||||
|
|
||||||
|
if ($r->{success}) {
|
||||||
|
my $response = eval {
|
||||||
|
my $j = JSON::XS->new->utf8->relaxed;
|
||||||
|
return $j->decode ($r->{content});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (defined $response) {
|
||||||
|
# lets make another query, this time with random picture
|
||||||
|
my $page = irand int ($response->{photos}->{total} / 500);
|
||||||
|
$oauth_timestamp = time ();
|
||||||
|
$oauth_nonce = mknonce ();
|
||||||
|
$oauth_signature = flickerSignReq (
|
||||||
|
nojsoncallback => 1,
|
||||||
|
oauth_nonce => $oauth_nonce,
|
||||||
|
format => 'json',
|
||||||
|
oauth_consumer_key => $flickr_consumer_key,
|
||||||
|
oauth_timestamp => $oauth_timestamp,
|
||||||
|
type => 'search_text',
|
||||||
|
content_type => 1,
|
||||||
|
media => 'photos',
|
||||||
|
method => 'flickr.photos.search',
|
||||||
|
text => $text,
|
||||||
|
page => $page,
|
||||||
|
per_page => 500,
|
||||||
|
oauth_token => $flickr_access_token,
|
||||||
|
oauth_token_secret => $flickr_access_token_secret,
|
||||||
|
oauth_signature_method => 'HMAC-SHA1',
|
||||||
|
oauth_version => '1.0'
|
||||||
|
);
|
||||||
|
|
||||||
|
$url = $flickr_api_url . sprintf (
|
||||||
|
'?nojsoncallback=1&oauth_nonce=%s&format=json&oauth_consumer_key=%s&oauth_timestamp=%s&oauth_signature_method=HMAC-SHA1&oauth_version=1.0&oauth_token=%s&oauth_signature=%s&method=flickr.photos.search&content_type=1&media=photos&per_page=500&page=%d&text=%s',
|
||||||
|
$oauth_nonce,
|
||||||
|
$flickr_consumer_key,
|
||||||
|
$oauth_timestamp,
|
||||||
|
$flickr_access_token,
|
||||||
|
uri_encode ($oauth_signature),
|
||||||
|
$page,
|
||||||
|
uri_encode ($text)
|
||||||
|
);
|
||||||
|
|
||||||
|
$http = HTTP::Tiny->new (timeout => 5);
|
||||||
|
$r = $http->get ($url);
|
||||||
|
|
||||||
|
if ($r->{success}) {
|
||||||
|
$response = eval {
|
||||||
|
my $j = JSON::XS->new->utf8->relaxed;
|
||||||
|
return $j->decode ($r->{content});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (defined $response) {
|
||||||
|
return $response;
|
||||||
|
} else {
|
||||||
|
cluck "Flickr api returns incorrect json: $r->{content}";
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cluck "Flickr api returns incorrect json: $r->{content}";
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cluck "Flickr api returns incorrect json: $r->{content}";
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cluck "HTTP status code not 200: $r->{status}, $r->{content}";
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub flickrSearchByTags {
|
||||||
|
my $flickr_access_token = shift;
|
||||||
|
my $flickr_access_token_secret = shift;
|
||||||
|
my $tags = shift;
|
||||||
|
|
||||||
|
my $oauth_timestamp = time ();
|
||||||
|
my $oauth_nonce = mknonce ();
|
||||||
|
|
||||||
|
my $oauth_signature = flickerSignReq (
|
||||||
|
nojsoncallback => 1,
|
||||||
|
oauth_nonce => $oauth_nonce,
|
||||||
|
format => 'json',
|
||||||
|
oauth_consumer_key => $flickr_consumer_key,
|
||||||
|
oauth_timestamp => $oauth_timestamp,
|
||||||
|
type => 'search_tags',
|
||||||
|
content_type => 1,
|
||||||
|
media => 'photos',
|
||||||
|
method => 'flickr.photos.search',
|
||||||
|
tags => $tags,
|
||||||
|
per_page => 1,
|
||||||
|
oauth_token => $flickr_access_token,
|
||||||
|
oauth_token_secret => $flickr_access_token_secret,
|
||||||
|
oauth_signature_method => 'HMAC-SHA1',
|
||||||
|
oauth_version => '1.0'
|
||||||
|
);
|
||||||
|
|
||||||
|
my $url = $flickr_api_url . sprintf (
|
||||||
|
'?nojsoncallback=1&oauth_nonce=%s&format=json&oauth_consumer_key=%s&oauth_timestamp=%s&oauth_signature_method=HMAC-SHA1&oauth_version=1.0&oauth_token=%s&oauth_signature=%s&method=flickr.photos.search&content_type=1&media=photos&per_page=1&tags=%s&tag_mode=all',
|
||||||
|
$oauth_nonce,
|
||||||
|
$flickr_consumer_key,
|
||||||
|
$oauth_timestamp,
|
||||||
|
$flickr_access_token,
|
||||||
|
uri_encode ($oauth_signature),
|
||||||
|
uri_encode ($tags)
|
||||||
|
);
|
||||||
|
|
||||||
|
my $http = HTTP::Tiny->new (timeout => 5);
|
||||||
|
my $r = $http->get ($url);
|
||||||
|
|
||||||
|
if ($r->{success}) {
|
||||||
|
my $response = eval {
|
||||||
|
my $j = JSON::XS->new->utf8->relaxed;
|
||||||
|
return $j->decode ($r->{content});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (defined $response) {
|
||||||
|
# lets make another query, this time with random picture
|
||||||
|
my $page = irand int ($response->{photos}->{total} / 500);
|
||||||
|
$oauth_timestamp = time ();
|
||||||
|
$oauth_nonce = mknonce ();
|
||||||
|
$oauth_signature = flickerSignReq (
|
||||||
|
nojsoncallback => 1,
|
||||||
|
oauth_nonce => $oauth_nonce,
|
||||||
|
format => 'json',
|
||||||
|
oauth_consumer_key => $flickr_consumer_key,
|
||||||
|
oauth_timestamp => $oauth_timestamp,
|
||||||
|
type => 'search_text',
|
||||||
|
content_type => 1,
|
||||||
|
media => 'photos',
|
||||||
|
method => 'flickr.photos.search',
|
||||||
|
tags => $tags,
|
||||||
|
page => $page,
|
||||||
|
per_page => 500,
|
||||||
|
oauth_token => $flickr_access_token,
|
||||||
|
oauth_token_secret => $flickr_access_token_secret,
|
||||||
|
oauth_signature_method => 'HMAC-SHA1',
|
||||||
|
oauth_version => '1.0'
|
||||||
|
);
|
||||||
|
|
||||||
|
$url = $flickr_api_url . sprintf (
|
||||||
|
'?nojsoncallback=1&oauth_nonce=%s&format=json&oauth_consumer_key=%s&oauth_timestamp=%s&oauth_signature_method=HMAC-SHA1&oauth_version=1.0&oauth_token=%s&oauth_signature=%s&method=flickr.photos.search&content_type=1&media=photos&per_page=500&page=%d&tags=%s&tag_mode=all',
|
||||||
|
$oauth_nonce,
|
||||||
|
$flickr_consumer_key,
|
||||||
|
$oauth_timestamp,
|
||||||
|
$flickr_access_token,
|
||||||
|
uri_encode ($oauth_signature),
|
||||||
|
$page,
|
||||||
|
uri_encode ($tags)
|
||||||
|
);
|
||||||
|
|
||||||
|
$http = HTTP::Tiny->new (timeout => 5);
|
||||||
|
$r = $http->get ($url);
|
||||||
|
|
||||||
|
if ($r->{success}) {
|
||||||
|
$response = eval {
|
||||||
|
my $j = JSON::XS->new->utf8->relaxed;
|
||||||
|
return $j->decode ($r->{content});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (defined $response) {
|
||||||
|
return $response;
|
||||||
|
} else {
|
||||||
|
cluck "Flickr api returns incorrect json: $r->{content}";
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cluck "Flickr api returns incorrect json: $r->{content}";
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cluck "Flickr api returns incorrect json: $r->{content}";
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cluck "HTTP status code not 200: $r->{status}, $r>{contenr}";
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub flickr_init {
|
||||||
|
my $backingfile = sprintf '%s/secrets.sqlite', $dir;
|
||||||
|
|
||||||
|
unless (-d $dir) {
|
||||||
|
make_path ($dir) or do {
|
||||||
|
say "Unable to create $dir: $OS_ERROR"; ## no critic (InputOutput::RequireCheckedSyscalls)
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
tie my %secret, 'SQLite_File', $backingfile || do {
|
||||||
|
say "[ERROR] Unable to tie to $backingfile: $OS_ERROR"; ## no critic (InputOutput::RequireCheckedSyscalls)
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (defined $flickr_verifier && $flickr_verifier) {
|
||||||
|
my $flickr_request_token = $secret{flickr_request_token};
|
||||||
|
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"; ## 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
my %accessToken = flickrAccessToken ($flickr_request_token, $flickr_request_token_secret, $flickr_verifier);
|
||||||
|
|
||||||
|
if (defined ($accessToken{oauth_token}) && defined ($accessToken{oauth_token_secret})) {
|
||||||
|
$secret{flickr_access_token} = $accessToken{oauth_token};
|
||||||
|
$secret{flickr_access_token_secret} = $accessToken{oauth_token_secret};
|
||||||
|
|
||||||
|
say sprintf ( ## no critic (InputOutput::RequireCheckedSyscalls)
|
||||||
|
'Access token (%s) and access token secret (%s) are in %s',
|
||||||
|
$accessToken{oauth_token},
|
||||||
|
$accessToken{oauth_token_secret},
|
||||||
|
$backingfile
|
||||||
|
);
|
||||||
|
|
||||||
|
untie %secret;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
my %req = flickrRequestToken ();
|
||||||
|
if (defined ($req{oauth_token}) && defined ($req{oauth_token_secret}) && defined ($req{oauth_token})) {
|
||||||
|
$secret{flickr_request_token} = $req{oauth_token};
|
||||||
|
$secret{flickr_request_token_secret} = $req{oauth_token_secret};
|
||||||
|
my $confirm_url = flickrAuthorization ($req{oauth_token});
|
||||||
|
|
||||||
|
if (defined $confirm_url) {
|
||||||
|
say "Please open this url in your browser and grant access for this app:\n$confirm_url"; ## no critic (InputOutput::RequireCheckedSyscalls)
|
||||||
|
say 'Do not forget to put oauth_verifier to config.json file and re-run this script to get access token'; ## no critic (InputOutput::RequireCheckedSyscalls)
|
||||||
|
say 'Note that you should be logged off from flickr account.'; ## no critic (InputOutput::RequireCheckedSyscalls)
|
||||||
|
untie %secret;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
untie %secret;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub flickr_test_login {
|
||||||
|
my $text = shift;
|
||||||
|
my $backingfile = sprintf '%s/secrets.sqlite', $dir;
|
||||||
|
|
||||||
|
unless (-d $dir) {
|
||||||
|
make_path ($dir) or do {
|
||||||
|
say "Unable to create $dir: $OS_ERROR"; ## no critic (InputOutput::RequireCheckedSyscalls)
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
tie my %secret, 'SQLite_File', $backingfile || do {
|
||||||
|
say "[ERROR] Unable to tie to $backingfile: $OS_ERROR"; ## no critic (InputOutput::RequireCheckedSyscalls)
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
my $flickr_access_token = $secret{flickr_access_token};
|
||||||
|
my $flickr_access_token_secret = $secret{flickr_access_token_secret};
|
||||||
|
untie %secret;
|
||||||
|
|
||||||
|
if (flickrTestLogin ($flickr_access_token, $flickr_access_token_secret)) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub flickr_by_tags {
|
||||||
|
my $text = shift;
|
||||||
|
my $backingfile = sprintf '%s/secrets.sqlite', $dir;
|
||||||
|
|
||||||
|
unless (-d $dir) {
|
||||||
|
make_path ($dir) or do {
|
||||||
|
say "Unable to create $dir: $OS_ERROR"; ## no critic (InputOutput::RequireCheckedSyscalls)
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
tie my %secret, 'SQLite_File', $backingfile || do {
|
||||||
|
say "[ERROR] Unable to tie to $backingfile: $OS_ERROR"; ## no critic (InputOutput::RequireCheckedSyscalls)
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
my $flickr_access_token = $secret{flickr_access_token};
|
||||||
|
my $flickr_access_token_secret = $secret{flickr_access_token_secret};
|
||||||
|
untie %secret;
|
||||||
|
|
||||||
|
# NB: I honestly query random page (among number of pages) of results from api, but always got first page,
|
||||||
|
# no matter what is shown in response' "page" parameter. Looks like bug in API. Try to little bit mitigate
|
||||||
|
# this bug via query 500 results per page, then we can select random result in this heap. But anyway, let's
|
||||||
|
# make this thing future proof and leave randomizer in page select.
|
||||||
|
my $result = flickrSearchByTags ($flickr_access_token, $flickr_access_token_secret, $text);
|
||||||
|
|
||||||
|
if ($result) {
|
||||||
|
if (defined ($result->{photos}) && defined ($result->{photos}->{photo})) {
|
||||||
|
my $item = irand int(@{$result->{photos}->{photo}});
|
||||||
|
$item = ${$result->{photos}->{photo}}[$item];
|
||||||
|
$item = sprintf 'https://live.staticflickr.com/%s/%s_%s_z.jpg', $item->{server}, $item->{id}, $item->{secret};
|
||||||
|
return $item;
|
||||||
|
} else {
|
||||||
|
cluck 'Flickr api returns empty search result list';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub flickr_by_text {
|
||||||
|
my $text = shift;
|
||||||
|
my $backingfile = sprintf '%s/secrets.sqlite', $dir;
|
||||||
|
|
||||||
|
unless (-d $dir) {
|
||||||
|
make_path ($dir) or do {
|
||||||
|
say "Unable to create $dir: $OS_ERROR"; ## no critic (InputOutput::RequireCheckedSyscalls)
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
tie my %secret, 'SQLite_File', $backingfile || do {
|
||||||
|
say "[ERROR] Unable to tie to $backingfile: $OS_ERROR"; ## no critic (InputOutput::RequireCheckedSyscalls)
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
my $flickr_access_token = $secret{flickr_access_token};
|
||||||
|
my $flickr_access_token_secret = $secret{flickr_access_token_secret};
|
||||||
|
untie %secret;
|
||||||
|
|
||||||
|
# NB: I honestly query random page (among number of pages) of results from api, but always got first page,
|
||||||
|
# no matter what is shown in response' "page" parameter. Looks like bug in API. Try to little bit mitigate
|
||||||
|
# this bug via query 500 results per page, then we can select random result in this heap. But anyway, let's
|
||||||
|
# make this thing future proof and leave randomizer in page select.
|
||||||
|
my $result = flickrSearchByText ($flickr_access_token, $flickr_access_token_secret, $text);
|
||||||
|
|
||||||
|
if ($result) {
|
||||||
|
if (defined ($result->{photos}) && defined ($result->{photos}->{photo})) {
|
||||||
|
my $item = irand int(@{$result->{photos}->{photo}});
|
||||||
|
$item = ${$result->{photos}->{photo}}[$item];
|
||||||
|
$item = sprintf 'https://live.staticflickr.com/%s/%s_%s_z.jpg', $item->{server}, $item->{id}, $item->{secret};
|
||||||
|
return $item;
|
||||||
|
} else {
|
||||||
|
cluck 'Flickr api returns empty search result list';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
@@ -44,7 +44,7 @@ sub fox {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cluck sprintf 'Server return status %s with message: %s', $r->{status}, $r->{reason};
|
carp sprintf 'Server return status %s with message: %s', $r->{status}, $r->{reason};
|
||||||
}
|
}
|
||||||
|
|
||||||
return $ret;
|
return $ret;
|
||||||
|
|||||||
41
lib/image.pm
Normal file
41
lib/image.pm
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package image;
|
||||||
|
|
||||||
|
use 5.018;
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use utf8;
|
||||||
|
use open qw (:std :utf8);
|
||||||
|
use flickr qw (flickr_by_tags);
|
||||||
|
|
||||||
|
use version; our $VERSION = qw (1.0);
|
||||||
|
use Exporter qw (import);
|
||||||
|
our @EXPORT_OK = qw (rabbit owl);
|
||||||
|
|
||||||
|
my $c = loadConf ();
|
||||||
|
my $dir = $c->{image}->{dir};
|
||||||
|
|
||||||
|
|
||||||
|
sub rabbit {
|
||||||
|
# rabbit, but bunny
|
||||||
|
my $url = flickr_by_tags ('animal,bunny');
|
||||||
|
|
||||||
|
if (defined $url) {
|
||||||
|
return $url;
|
||||||
|
} else {
|
||||||
|
return 'Нету кроликов, все разбежались.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub owl {
|
||||||
|
my $url = flickr_by_tags ('bird,owl');
|
||||||
|
|
||||||
|
if (defined $url) {
|
||||||
|
return $url;
|
||||||
|
} else {
|
||||||
|
return 'Нету сов, все разлетелись.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
|
|
||||||
|
# vim: set ft=perl noet ai ts=4 sw=4 sts=4:
|
||||||
62
lib/monkeyuser.pm
Normal file
62
lib/monkeyuser.pm
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
package monkeyuser;
|
||||||
|
|
||||||
|
use 5.018;
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
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 version; our $VERSION = qw (1.0);
|
||||||
|
use Exporter qw (import);
|
||||||
|
our @EXPORT_OK = qw (monkeyuser);
|
||||||
|
|
||||||
|
sub monkeyuser {
|
||||||
|
my $r;
|
||||||
|
my $ret = 'Нету Monkey User-ов, они все спрятались.';
|
||||||
|
my @link;
|
||||||
|
|
||||||
|
for (1..3) {
|
||||||
|
my $http = HTTP::Tiny->new (timeout => 3);
|
||||||
|
$r = $http->get ('https://www.monkeyuser.com/toc/');
|
||||||
|
|
||||||
|
if ($r->{success}) {
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
|
||||||
|
sleep 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($r->{success}) {
|
||||||
|
my $p = HTML::TokeParser->new(\$r->{content});
|
||||||
|
my @a;
|
||||||
|
|
||||||
|
do {
|
||||||
|
$#a = -1;
|
||||||
|
@a = $p->get_tag('a'); ## no critic (Variables::RequireLocalizedPunctuationVars)
|
||||||
|
|
||||||
|
if (defined $a[0][1]->{class} && $a[0][1]->{class} eq 'lazyload small-image') {
|
||||||
|
if (defined $a[0][1]->{'data-src'} && ($a[0][1]->{'data-src'} !~ /adlitteram/)) {
|
||||||
|
push @link, $a[0][1]->{'data-src'};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} while ($#{$a[0]} > 1);
|
||||||
|
|
||||||
|
if ($#link > 0) {
|
||||||
|
$ret = sprintf 'https://www.monkeyuser.com%s', $link [irand (1 + $#link)];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cluck sprintf 'Server return status %s with message: %s', $r->{status}, $r->{reason};
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
|
|
||||||
|
# vim: set ft=perl noet ai ts=4 sw=4 sts=4:
|
||||||
Reference in New Issue
Block a user