From 51ffaecc06021d40908eec179b4395953a912cdb Mon Sep 17 00:00:00 2001 From: Guillermo Ramos Date: Mon, 2 Sep 2019 00:33:28 +0200 Subject: tgserver: receive images + send documents --- lib/TgLib/Api.pm | 57 ++++++++++++++++++++++++++++++++++- tgserver | 92 +++++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 131 insertions(+), 18 deletions(-) diff --git a/lib/TgLib/Api.pm b/lib/TgLib/Api.pm index 66c808f..73aee4b 100644 --- a/lib/TgLib/Api.pm +++ b/lib/TgLib/Api.pm @@ -5,6 +5,7 @@ use warnings; use JSON qw; use HTTP::Request; +use HTTP::Request::Common qw; use LWP::UserAgent; use Data::Dumper; @@ -14,6 +15,7 @@ our @EXPORT = qw; sub new { my ($class, $token, $logger) = @_; return bless { uri => "https://api.telegram.org/bot$token", + file_uri => "https://api.telegram.org/file/bot$token", ua => LWP::UserAgent->new, logger => $logger }, $class; } @@ -35,7 +37,7 @@ sub get_updates { } else { my $updates = decode_json($resp->content)->{'result'}; # TODO why does `decode_json` not do this work? - map { utf8::encode($_->{'message'}{'text'}) } @$updates; + map { utf8::encode($_->{'message'}{'text'}) if exists $_->{'message'}{'text'} } @$updates; $logger->info(sprintf "Received %d updates from chats %s\n", scalar(@$updates), join(", ", map { $_->{'message'}{'chat'}{'id'} } @$updates)); @@ -61,4 +63,57 @@ sub send_message { } } +sub send_document { + my ($self, $chat_id, $photo) = @_; + my $logger = $self->{'logger'}; + my $uri = "$self->{'uri'}/sendDocument"; + my $content = {'chat_id' => $chat_id, + 'caption' => 'Tenga, ayúdese', + 'document' => [undef, 'cosa.png', Content => $photo]}; + + my $req = POST $uri, 'Content-Type' => "multipart/form-data", 'Content' => $content; + $logger->info("Sending photo to $chat_id\n"); + $logger->debug(sprintf "Request:\n%s\n", Dumper($req)); # DEBUG + + my $resp = $self->{'ua'}->request($req); + $logger->debug(sprintf "Response:\n%s\n", Dumper($resp)); + if ($resp->is_error()) { + print decode_json($resp->content)->{'description'}; + die $resp->message; + } +} + +sub get_file { + my ($self, $file_id) = @_; + my $logger = $self->{'logger'}; + my $uri = "$self->{'uri'}/getFile"; + my $content = encode_json {'file_id' => $file_id}; + + my $req = HTTP::Request->new("POST", $uri, + ["Content-Type", "application/json"], $content); + $logger->debug(sprintf "Request:\n%s\n", Dumper($req)); + + my $resp = $self->{'ua'}->request($req); + $logger->debug(sprintf "Response:\n%s\n", Dumper($resp)); + if ($resp->is_error()) { + die $resp->message; + } else { + my $file_path = decode_json($resp->content)->{'result'}{'file_path'}; + $logger->info("Getting file $file_id (file_path: $file_path)...\n"); + + my $uri = "$self->{'file_uri'}/$file_path"; + my $req = HTTP::Request->new("GET", $uri); + $logger->debug(sprintf "Request:\n%s\n", Dumper($req)); + + my $resp = $self->{'ua'}->request($req); + $logger->debug(sprintf "Response:\n%s\n", Dumper($resp)); + + if ($resp->is_error()) { + die $resp->content; + } else { + return $resp->content; + } + } +} + 1; diff --git a/tgserver b/tgserver index e624ae2..589054b 100755 --- a/tgserver +++ b/tgserver @@ -5,11 +5,18 @@ # Run `tgserver -h` for quick help, or `tgserver -h -v` for full manual. ################################################################################ +use strict; +use warnings; + +use Try::Tiny; + $main::VERSION = "0.1.1"; use Getopt::Long qw(:config auto_version); use Pod::Usage qw; use Data::Dumper; +use MIME::Base64 qw; +use JSON qw; use FindBin; use lib "$FindBin::Bin/lib"; @@ -44,28 +51,75 @@ while (1) { $cache->offset($update->{'update_id'}+1); $logger->debug(sprintf "Update %s", Dumper($update)); - my $text = $update->{'message'}{'text'}; - my $chat_id = $update->{'message'}{'chat'}{'id'}; - $logger->info("Received from chat $chat_id: '$text'\n"); - - use IPC::Open2 qw; - my $pid = open2(my $progr, my $progw, "@ARGV"); - print $progw $text; - close($progw); - my $response = join "", <$progr>; - chomp $response; - $logger->debug("'$text' -> @ARGV -> '$response'\n"); - close($progr); - - if ($response) { - my $api = TgLib::Api->new($TOKEN, $logger); - $api->send_message($chat_id, $response); + my $msg = $update->{'message'}; + if (exists $msg->{'photo'}) { + handle_photo($msg); } else { - $logger->warn("Empty response, skipping\n"); + handle_text($msg); } } } +sub handle_photo { + my $msg = shift; + my $photos = $msg->{'photo'}; + my $chat_id = $msg->{'chat'}{'id'}; + my $photo = (sort { $b->{'width'} <=> $a->{'width'} } @$photos)[0]; + $logger->info(sprintf "Received photo %s (size=%d)\n", $photo->{'file_id'}, $photo->{'file_size'}); + + my $file = $api->get_file($photo->{'file_id'}); + + $ENV{'TGUTILS_TYPE'} = 'IMAGE'; + my $response = pipe_send($file, @ARGV); + my $type = ref $response eq 'HASH' ? $response->{'type'} : undef; + if ($type eq 'DOCUMENT') { + $api->send_document($chat_id, decode_base64 $response->{'content'}); + } else { + $api->send_message($chat_id, $response); + } +} + +sub handle_text { + my $msg = shift; + my $text = $msg->{'text'}; + my $chat_id = $msg->{'chat'}{'id'}; + $logger->info("Received from chat $chat_id: '$text'\n"); + + $ENV{'TGUTILS_TYPE'} = 'TEXT'; + my $response = pipe_send($text, @ARGV); + if ($response) { + $api->send_message($chat_id, $response); + } else { + $logger->warn("Empty response, skipping\n"); + } +} + +sub pipe_send { + my ($content, @cmd) = @_; + + use IPC::Open2 qw; + my $pid = open2(my $progr, my $progw, @cmd); + + print $progw $content; + close($progw); + + # Don't read a single line + my $oldsep = $/; + $/ = undef; + + binmode($progr); + my $response = <$progr>; + close($progr); + + $/ = $oldsep; + + waitpid $pid, 0; # collect the child process + chomp $response; + # $logger->debug("'$content' -> @ARGV -> '$response'\n"); + + return try { decode_json $response } catch { $response }; +} + __END__ @@ -83,6 +137,10 @@ B [I] -- I =over +=item B<--on-image>=I + +Command to launch whenever an image is received + =item B<--token>=I, B<-t> I Bot token (see B) -- cgit v1.2.3 From 81c7d08f10d12edd2fe224c918e7eafb912c11c0 Mon Sep 17 00:00:00 2001 From: Guillermo Ramos Date: Mon, 24 Feb 2020 13:22:05 +0100 Subject: Allow custom captions from document replies --- lib/TgLib/Api.pm | 4 ++-- tgserver | 26 ++++++++++++++------------ 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/lib/TgLib/Api.pm b/lib/TgLib/Api.pm index 73aee4b..b0a66bf 100644 --- a/lib/TgLib/Api.pm +++ b/lib/TgLib/Api.pm @@ -64,11 +64,11 @@ sub send_message { } sub send_document { - my ($self, $chat_id, $photo) = @_; + my ($self, $chat_id, $photo, $caption) = @_; my $logger = $self->{'logger'}; my $uri = "$self->{'uri'}/sendDocument"; my $content = {'chat_id' => $chat_id, - 'caption' => 'Tenga, ayúdese', + 'caption' => $caption, 'document' => [undef, 'cosa.png', Content => $photo]}; my $req = POST $uri, 'Content-Type' => "multipart/form-data", 'Content' => $content; diff --git a/tgserver b/tgserver index 589054b..ac221fc 100755 --- a/tgserver +++ b/tgserver @@ -65,18 +65,14 @@ sub handle_photo { my $photos = $msg->{'photo'}; my $chat_id = $msg->{'chat'}{'id'}; my $photo = (sort { $b->{'width'} <=> $a->{'width'} } @$photos)[0]; - $logger->info(sprintf "Received photo %s (size=%d)\n", $photo->{'file_id'}, $photo->{'file_size'}); + $logger->info(sprintf "Received photo %s (size=%d) from chat %s\n", + $photo->{'file_id'}, $photo->{'file_size'}, $chat_id); my $file = $api->get_file($photo->{'file_id'}); $ENV{'TGUTILS_TYPE'} = 'IMAGE'; my $response = pipe_send($file, @ARGV); - my $type = ref $response eq 'HASH' ? $response->{'type'} : undef; - if ($type eq 'DOCUMENT') { - $api->send_document($chat_id, decode_base64 $response->{'content'}); - } else { - $api->send_message($chat_id, $response); - } + reply($chat_id, $response); } sub handle_text { @@ -87,7 +83,17 @@ sub handle_text { $ENV{'TGUTILS_TYPE'} = 'TEXT'; my $response = pipe_send($text, @ARGV); - if ($response) { + reply($chat_id, $response); +} + +sub reply { + my $chat_id = shift; + my $response = shift; + my $type = ref $response eq 'HASH' ? $response->{'type'} : undef; + if ($type eq 'DOCUMENT') { + my $caption = $response->{'caption'}; + $api->send_document($chat_id, decode_base64 $response->{'content'}, $caption); + } elsif ($response) { $api->send_message($chat_id, $response); } else { $logger->warn("Empty response, skipping\n"); @@ -137,10 +143,6 @@ B [I] -- I =over -=item B<--on-image>=I - -Command to launch whenever an image is received - =item B<--token>=I, B<-t> I Bot token (see B) -- cgit v1.2.3