#!/usr/bin/perl
#
# by Stefan "Tommie" Tomanek
use strict;
use vars qw($VERSION %IRSSI);
$VERSION = '20220104';
%IRSSI = (
authors => 'Stefan \'tommie\' Tomanek, bw1',
contact => '[email protected]',
name => 'leodict',
description => 'translates via dict.leo.org',
license => 'GPLv2',
url => 'http://irssi.org/scripts/',
modules => 'Mojo::UserAgent Encode JSON::PP Mojo::DOM Getopt::Long POSIX',
commands => "leodict",
selfcheckcmd=> 'leodict -chec',
);
use vars qw($forked);
use utf8;
use Encode;
use Irssi 20020324;
use JSON::PP;
use Mojo::DOM;
use Getopt::Long qw(GetOptionsFromString);
use Mojo::UserAgent;
use POSIX;
# global
my %gresult;
my $lang;
my $dlang= 'englisch-deutsch/';
my $help;
my $browse;
my $paste;
my $word;
my $dir;
my $ddir= '';
my $check;
# for fork
my $ftext;
my %fresult;
sub draw_box ($$$$) {
my ($title, $text, $footer, $colour) = @_;
my $box = '';
$box .= '%R,--[%n%9%U'.$title.'%U%9%R]%n'."\n";
foreach (split(/\n/, $text)) {
$box .= '%R|%n '.$_."\n";
}
$box .= '%R`--<%n'.$footer.'%R>->%n';
$box =~ s/%.//g unless $colour;
return $box;
}
sub show_help() {
my $help = "LeoDict $VERSION
SYNOPSIS
/leodict [OPTION] [OPTION]
searches dict.leo.org for appropiate translations
DESCRIPTION
-p
paste the translations to the current channel or query
The number of translations is limited by the setting
'leodict_paste_max_translations'
-b
open dict.leo.org in your web browser (uses openurl.pl)
-from from German
-to to German
-both from and to German
-en English
-fr French
-es Spanish
-it Italian
-zh Chinese
-ru Russian
-pt Portuguese
-pl Polish
-chec selfcheck
SETTINGS
'leodict_default_options'
example: -it -from
'leodict_paste_max_translations'
'leodict_paste_beautify'
'leodict_http_proxy_address'
example: 127.0.0.1
defaults to none, meaning no proxy will be used for requests.
despite the name, does not have to be http proxy.
'leodict_http_proxy_port'
example: 9050
defaults to 0, but must be changed if proxy address is not none.
'leodict_http_proxy_type'
supported: socks, https, http
";
my $text='';
foreach (split(/\n/, $help)) {
$_ =~ s/^\/(.*)$/%9\/$1%9/;
$text .= $_."\n";
}
print CLIENTCRAP draw_box($IRSSI{name}, $text, "help", 1);
}
sub parser {
my %ignore=(
'Suchwort' => 1,
'Beispiele' => 1,
'Orthographisch ähnliche Wörter' => 1,
'Aus dem Umfeld der Suche' => 1,
'Forumsdiskussionen, die den Suchbegriff enthalten' =>1,
#'Substantive'
#'Verben'
#'Adjektive / Adverbien'
#'Phrasen'
);
%fresult=();
# tables
unless (defined $ftext) {
%fresult=('Error'=>[['no data']]);
return;
}
my $dom = Mojo::DOM->new($ftext);
foreach my $tbl ( $dom->find('table')->each ) {
# head
my $thead =$tbl->at('thead');
next unless (defined $thead );
my $headname = $thead->descendant_nodes->last->to_string;
next if (exists $ignore{ $headname } );
# rows
my @rows=();
foreach my $row ( $tbl->find('tr')->each) {
# colums
my @columns=();
foreach my $col ( $row->find('td')->each ) {
my $co = $col->to_string;
$co =~ s/<.*?>//sg;
if ( length($co) >2 ) {
push(@columns ,$co);
}
}
if ( scalar(@columns) > 0 ) {
push(@rows, [@columns]);
}
}
$fresult{ $headname } = [ @rows ];
}
}
sub get_page ($) {
my ($url) = @_;
#return get('http://dict.leo.org/?search='.$word.'&relink=off');
my $ua = Mojo::UserAgent->new;
# Add proxy to Mojo if needed
my $proxy_addr = Irssi::settings_get_str('leodict_http_proxy_address');
my $proxy_port = Irssi::settings_get_int('leodict_http_proxy_port');
my $proxy_type = Irssi::settings_get_str('leodict_http_proxy_type');
if ($proxy_addr ne 'none') {
# Socks proxy
if ($proxy_type eq 'socks' || $proxy_type eq 'https') {
$ua->proxy->http("$proxy_type://$proxy_addr:$proxy_port")->https("$proxy_type://$proxy_addr:$proxy_port");
}
# Must be http proxy
else {
$ua->proxy->http("$proxy_type://$proxy_addr:$proxy_port");
}
}
my $res;
eval {
$res=$ua->get($url)->result;
};
if (defined $res && $res->is_success) {
$ftext = $res->body;
utf8::decode($ftext);
} else {
$ftext=undef;
}
}
sub call_openurl ($) {
my ($url) = @_;
no strict "refs";
# check for a loaded openurl
if (defined &{ "Irssi::Script::openurl::launch_url" } ) {
&{ "Irssi::Script::openurl::launch_url" }($url);
} else {
print CLIENTCRAP "%R>>%n Please install openurl.pl";
}
}
sub translate ($$$) {
my ($url, $target, $server) = @_;
my ($rh, $wh);
pipe($rh, $wh);
if ($forked) {
print CLIENTCRAP "%R>>%n Please wait until your earlier request has been finished.";
return;
}
# Validate proxy if needed
my $proxy_addr = Irssi::settings_get_str('leodict_http_proxy_address');
my $proxy_port = Irssi::settings_get_int('leodict_http_proxy_port');
my $proxy_type = Irssi::settings_get_str('leodict_http_proxy_type');
if ($proxy_addr ne 'none') {
if ($proxy_type ne 'socks' && $proxy_type ne 'https' && $proxy_type ne 'http') {
print CLIENTCRAP "%R>>%n Invalid proxy type: $proxy_type.";
return;
}
if ($proxy_port eq 0) {
print CLIENTCRAP "%R>>%n Please specify a proxy port.";
return;
}
}
my $pid = fork();
$forked = 1;
if ($pid > 0) {
print CLIENTCRAP "%R>>%n Please wait..." unless $target;
close $wh;
Irssi::pidwait_add($pid);
my $pipetag;
my @args = ($rh, \$pipetag, $target, $server);
$pipetag = Irssi::input_add(fileno($rh), INPUT_READ, \&pipe_input, \@args);
} else {
get_page($url);
parser();
print($wh encode_json(\%fresult));
close($wh);
POSIX::_exit(1);
}
}
sub one_site {
my ($site, $cat) = @_;
my @res;
foreach my $r ( @{$gresult{$cat}} ) {
push @res,$r->[$site];
}
return [@res];
}
sub pipe_input ($) {
my ($rh, $pipetag, $target, $tag) = @{$_[0]};
$forked = 0;
local $\;
my $res=<$rh>;
close $rh;
return if (length($res) <5);
%gresult = %{decode_json( $res )};
Irssi::input_remove($$pipetag);
if ($target eq '') {
show_translations(\%gresult, $word);
} else {
my $server = Irssi::server_find_tag($tag);
my $witem = $server->window_item_find($target);
paste_translations(\%gresult, $word, $witem) if $witem;
}
}
sub show_translations($$) {
my %trans = %{$_[0]};
my $word = $_[1];
self_check(\%trans) if ( defined $check );
if (%trans) {
my $text;
foreach my $k (keys %trans) {
$text .= "== $k ==\n";
foreach (@{ $trans{$k} }) {
$text .= "%U".$_->[0]."%U \n";
$text .= " `-> ".$_->[1]."\n";
}
}
my $term_charset= Irssi::settings_get_str('term_charset');
if ('UTF-8' ne $term_charset) {
$text= encode($term_charset, $text);
}
print CLIENTCRAP draw_box('LeoDict', $text, $word, 1);
} else {
print CLIENTCRAP "%R>>>%n No translations found (".$word.").";
}
}
sub paste_translations ($$) {
my ($trans, $word, $target) = @_;
return unless ($target->{type} eq "CHANNEL" || $target->{type} eq "QUERY");
if (%{ $trans }) {
my $text;
my $beauty = Irssi::settings_get_bool('leodict_paste_beautify');
my $max = Irssi::settings_get_int('leodict_paste_max_translations');
foreach my $k (keys %{ $trans }) {
$text .= "== $k ==\n";
my $i = 0;
foreach (@{ $trans->{$k}}) {
if ($i < $max || $max == 0) {
if ($beauty) {
$text .= $_->[0]." \n";
$text .= " `-> ".$_->[1]."\n";
} else {
$text .= $_->[0].' => '.$_->[1]."\n";
}
$i++;
} else {
$text .= '...'."\n";
last;
}
}
}
my $msg = $text;
$msg = draw_box('LeoDict', $text, $word, 0) if $beauty;
$target->command('MSG '.$target->{name}. ' '.$_) foreach (split(/\n/, $msg));
}
}
#https://dict.leo.org/englisch-deutsch/word
#https://dict.leo.org/franz%C3%B6sisch-deutsch/word
#https://dict.leo.org/spanisch-deutsch/word
#https://dict.leo.org/italienisch-deutsch/word
#https://dict.leo.org/chinesisch-deutsch/word
#https://dict.leo.org/russisch-deutsch/word
#https://dict.leo.org/portugiesisch-deutsch/word
#https://dict.leo.org/polnisch-deutsch/word
#https://dict.leo.org/polnisch-deutsch/word?side=left pl -> de
#https://dict.leo.org/polnisch-deutsch/word?side=right pl <- de
my %options = (
"from" => sub {$dir= '?side=right';},
"to" => sub {$dir= '?side=left';},
"both" => sub {$dir= '';},
"en" => sub {$lang = 'englisch-deutsch/'; },
"fr" => sub {$lang = 'franz%C3%B6sisch-deutsch/'; },
"es" => sub {$lang = 'spanisch-deutsch/'; },
"it" => sub {$lang = 'italienisch-deutsch/'; },
"zh" => sub {$lang = 'chinesisch-deutsch/'; },
"ru" => sub {$lang = 'russisch-deutsch/'; },
"pt" => sub {$lang = 'portugiesisch-deutsch/'; },
"pl" => sub {$lang = 'polnisch-deutsch/'; },
"h" => \$help,
"b" => \$browse,
"p" => \$paste,
"chec" => \$check,
);
sub cmd_leodict ($$$) {
my ($args, $server, $witem) = @_;
utf8::decode($args);
my $burl = "https://dict.leo.org/";
my $url;
$lang= $dlang;
$dir= $ddir;
undef $help;
undef $browse;
undef $paste;
undef $check;
my ($ret, $arg) = GetOptionsFromString($args, %options);
$word= $arg->[0];
$url=$burl.$lang.$word.$dir;
if (defined $help) {
show_help();
return();
}
if (defined $browse) {
call_openurl($url);
return();
}
if (defined $paste) {
#paste_translations($_, $witem) if $witem;
return unless defined $witem;
return unless defined $server;
translate($url, $witem->{name}, $witem->{server}->{tag});
} elsif (defined $check) {
$url=$burl.'englisch-deutsch/'.'tree'.$dir;
translate($url,'', '');
} else {
#show_translations($_);
translate($url,'', '');
}
}
sub self_check {
my ( $tr ) =@_;
my $s='ok';
Irssi::print("selfcheck: categorys ".scalar( keys %$tr ));
my $count=0;
foreach my $n ( keys %$tr ) {
Irssi::print("selfcheck: category $n ".scalar( @{$tr->{$n}} ));
$count +=scalar( @{$tr->{$n}} );
}
Irssi::print("selfcheck: results $count");
if ( scalar( keys %$tr ) <4 ) {
$s='Error: categorys ('.scalar( keys %$tr ).')';
} elsif ( $count < 35 ) {
$s="Error: results ($count)";
}
Irssi::print("selfcheck: $s");
my $schs = exists $Irssi::Script::{'selfcheckhelperscript::'};
Irssi::command("selfcheckhelperscript $s") if ( $schs );
}
sub sig_setup_changed {
my $args =Irssi::settings_get_str('leodict_default_options');
my ($ret, $arg) = GetOptionsFromString($args, %options);
$dlang=$lang;
$ddir=$dir;
}
Irssi::signal_add('setup changed', 'sig_setup_changed');
Irssi::command_bind('leodict', 'cmd_leodict');
Irssi::command_set_options('leodict', join(" ",keys %options));
Irssi::settings_add_str($IRSSI{'name'}, 'leodict_default_options', '-en -both');
Irssi::settings_add_int($IRSSI{'name'}, 'leodict_paste_max_translations', 2);
Irssi::settings_add_bool($IRSSI{'name'}, 'leodict_paste_beautify', 1);
Irssi::settings_add_str($IRSSI{'name'}, 'leodict_http_proxy_address', 'none');
Irssi::settings_add_int($IRSSI{'name'}, 'leodict_http_proxy_port', 0);
Irssi::settings_add_str($IRSSI{'name'}, 'leodict_http_proxy_type', 'none');
sig_setup_changed();
print CLIENTCRAP "%B>>%n ".$IRSSI{name}." ".$VERSION." loaded: /leodict -h for help";
# vim:set ts=8 sw=4: