X-Git-Url: https://git.sommitrealweird.co.uk/twirssi-net-twitter-lite.git/blobdiff_plain/f53ed11a5dd9561382143a06cb2e1e8d4b5f126b..c119e650820fc03f4ffa5d6ecfe5c1a1332bd7d5:/twirssi.pl diff --git a/twirssi.pl b/twirssi.pl index 660a49c..3cb6df8 100644 --- a/twirssi.pl +++ b/twirssi.pl @@ -6,23 +6,22 @@ use HTML::Entities; use File::Temp; use LWP::Simple; use Data::Dumper; -use Net::Identica; use Net::Twitter; $Data::Dumper::Indent = 1; use vars qw($VERSION %IRSSI); -$VERSION = "2.0.6"; -my ($REV) = '$Rev: 484 $' =~ /(\d+)/; +$VERSION = "2.1.2"; +my ($REV) = '$Rev: 523 $' =~ /(\d+)/; %IRSSI = ( authors => 'Dan Boger', contact => 'zigdon@gmail.com', name => 'twirssi', - description => 'Send twitter/identica updates using /tweet or /dent. ' + description => 'Send twitter updates using /tweet. ' . 'Can optionally set your bitlbee /away message to same', license => 'GNU GPL v2', url => 'http://twirssi.com', - changed => '$Date: 2009-02-21 13:53:25 -0800 (Sat, 21 Feb 2009) $', + changed => '$Date: 2009-03-07 14:09:03 -0800 (Sat, 07 Mar 2009) $', ); my $window; @@ -35,6 +34,7 @@ my %nicks; my %friends; my %tweet_cache; my %id_map; +my $failwhale = 0; my %irssi_to_mirc_colors = ( '%k' => '01', '%r' => '05', @@ -325,7 +325,7 @@ sub cmd_switch { } } -sub cmd_logout_twitter { +sub cmd_logout { my ( $data, $server, $win ) = @_; $data =~ s/^\s+|\s+$//g; @@ -344,134 +344,49 @@ sub cmd_logout_twitter { } } -sub cmd_logout_identica { - my ( $data, $server, $win ) = @_; - - $data =~ s/^\s+|\s+$//g; - $data = $user unless $data; - return unless &valid_username($data); - - ¬ice("Logging out $data..."); - $twits{$data}->end_session(); - delete $twits{$data}; - undef $twit; - if ( keys %twits ) { - &cmd_switch( ( keys %twits )[0], $server, $win ); - } else { - Irssi::timeout_remove($poll) if $poll; - undef $poll; - } -} - -sub cmd_login_twitter { +sub cmd_login { my ( $data, $server, $win ) = @_; my $pass; if ($data) { ( $user, $pass ) = split ' ', $data, 2; - } elsif ( my $autouser = Irssi::settings_get_str("twitter_usernames_twitter") - and my $autopass = Irssi::settings_get_str("twitter_passwords_twitter") ) + } elsif ( my $autouser = Irssi::settings_get_str("twitter_usernames") + and my $autopass = Irssi::settings_get_str("twitter_passwords") ) { my @user = split /\s*,\s*/, $autouser; my @pass = split /\s*,\s*/, $autopass; - if ( @user != @pass ) { - ¬ice("Number of usernames doesn't match " - . "the number of passwords - auto-login failed" ); - } else { - my ( $u, $p ); - while ( @user and @pass ) { - $u = shift @user; - $p = shift @pass; - &cmd_login_twitter("$u $p"); + + # if a password ends with a '\', it was meant to escape the comma, and + # it should be concatinated with the next one + my @unescaped; + while (@pass) { + my $p = shift @pass; + while ($p =~ /\\$/ and @pass) { + $p .= ",". shift @pass; } - return; + push @unescaped, $p; } - } else { - ¬ice("/twitter_login requires either a username and password " - . "or twitter_usernames_twitter and twitter_passwords_twitter to be set." ); - return; - } - %friends = %nicks = (); - - $twit = Net::Twitter->new( - username => $user, - password => $pass, - source => "twirssi" - ); - - unless ( $twit->verify_credentials() ) { - ¬ice("Login as $user failed"); - $twit = undef; - if ( keys %twits ) { - &cmd_switch( ( keys %twits )[0], $server, $win ); - } - return; - } - - if ($twit) { - my $rate_limit = $twit->rate_limit_status(); - if ( $rate_limit and $rate_limit->{remaining_hits} < 1 ) { - ¬ice( - "Rate limit exceeded, try again after $rate_limit->{reset_time}" - ); - $twit = undef; - return; - } - - $twits{$user} = $twit; - Irssi::timeout_remove($poll) if $poll; - $poll = Irssi::timeout_add( &get_poll_time * 1000, \&get_updates, "" ); - ¬ice("Logged in as $user, loading friends list..."); - &load_friends(); - ¬ice( "loaded friends: ", scalar keys %friends ); - if ( Irssi::settings_get_bool("twirssi_first_run") ) { - Irssi::settings_set_bool( "twirssi_first_run", 0 ); - unless ( exists $friends{twirssi} ) { - ¬ice("Welcome to twirssi!" - . " Perhaps you should add \@twirssi to your friends list," - . " so you can be notified when a new version is release?" - . " Just type /twitter_friend twirssi." ); - } - } - %nicks = %friends; - $nicks{$user} = 0; - &get_updates; - } else { - ¬ice("Login failed"); - } -} - -sub cmd_login_identica { - my ( $data, $server, $win ) = @_; - my $pass; - if ($data) { - ( $user, $pass ) = split ' ', $data, 2; - } elsif ( my $autouser = Irssi::settings_get_str("twitter_usernames_identica") - and my $autopass = Irssi::settings_get_str("twitter_passwords_identica") ) - { - my @user = split /\s*,\s*/, $autouser; - my @pass = split /\s*,\s*/, $autopass; - if ( @user != @pass ) { + if ( @user != @unescaped ) { ¬ice("Number of usernames doesn't match " . "the number of passwords - auto-login failed" ); } else { my ( $u, $p ); - while ( @user and @pass ) { + while ( @user and @unescaped ) { $u = shift @user; - $p = shift @pass; - &cmd_login_identica("$u $p"); + $p = shift @unescaped; + &cmd_login("$u $p"); } return; } } else { - ¬ice("/identica_login requires either a username and password " - . "or twitter_usernames_identica and twitter_passwords_identica to be set." ); + ¬ice("/twitter_login requires either a username and password " + . "or twitter_usernames and twitter_passwords to be set." ); return; } %friends = %nicks = (); - $twit = Net::Identica->new( + $twit = Net::Twitter->new( username => $user, password => $pass, source => "twirssi" @@ -513,13 +428,13 @@ sub cmd_login_identica { } %nicks = %friends; $nicks{$user} = 0; - &get_updates; + return 1; } else { ¬ice("Login failed"); } } -sub cmd_add_search_twitter { +sub cmd_add_search { my ( $data, $server, $win ) = @_; unless ( $twit and $twit->can('search') ) { @@ -545,33 +460,7 @@ sub cmd_add_search_twitter { ¬ice("Added subscription for '$data'"); } -sub cmd_add_search_identica { - my ( $data, $server, $win ) = @_; - - unless ( $twit and $twit->can('search') ) { - ¬ice("ERROR: Your version of Net::Identica ($Net::Identica::VERSION) " - . "doesn't support searches." ); - return; - } - - $data =~ s/^\s+|\s+$//; - $data = lc $data; - - unless ($data) { - ¬ice("Usage: /twitter_subscribe "); - return; - } - - if ( exists $id_map{__searches}{$user}{$data} ) { - ¬ice("Already had a subscription for '$data'"); - return; - } - - $id_map{__searches}{$user}{$data} = 1; - ¬ice("Added subscription for '$data'"); -} - -sub cmd_del_search_twitter { +sub cmd_del_search { my ( $data, $server, $win ) = @_; unless ( $twit and $twit->can('search') ) { @@ -596,31 +485,6 @@ sub cmd_del_search_twitter { ¬ice("Removed subscription for '$data'"); } -sub cmd_del_search_identica { - my ( $data, $server, $win ) = @_; - - unless ( $twit and $twit->can('search') ) { - ¬ice("ERROR: Your version of Net::Identica ($Net::Identica::VERSION) " - . "doesn't support searches." ); - return; - } - $data =~ s/^\s+|\s+$//; - $data = lc $data; - - unless ($data) { - ¬ice("Usage: /identica_unsubscribe "); - return; - } - - unless ( exists $id_map{__searches}{$user}{$data} ) { - ¬ice("No subscription found for '$data'"); - return; - } - - delete $id_map{__searches}{$user}{$data}; - ¬ice("Removed subscription for '$data'"); -} - sub cmd_list_search { my ( $data, $server, $win ) = @_; @@ -653,7 +517,7 @@ sub cmd_upgrade { } my $md5; - unless ($data) { + unless ( $data or Irssi::settings_get_bool("twirssi_upgrade_beta") ) { eval { use Digest::MD5; }; if ($@) { @@ -687,11 +551,14 @@ sub cmd_upgrade { } } - my $URL = "http://twirssi.com/twirssi.pl"; + my $URL = + Irssi::settings_get_bool("twirssi_upgrade_beta") + ? "http://github.com/zigdon/twirssi/raw/master/twirssi.pl" + : "http://twirssi.com/twirssi.pl"; ¬ice("Downloading twirssi from $URL"); LWP::Simple::getstore( $URL, "$loc.upgrade" ); - unless ($data) { + unless ( $data or Irssi::settings_get_bool("twirssi_upgrade_beta") ) { unless ( open( NEW, "$loc.upgrade" ) ) { ¬ice( "Failed to read $loc.upgrade. Check that /set twirssi_location is set to the correct location." @@ -783,7 +650,7 @@ sub get_updates { return unless &logged_in($twit); my ( $fh, $filename ) = File::Temp::tempfile(); - binmode($fh, ":utf8"); + binmode( $fh, ":utf8" ); my $pid = fork(); if ($pid) { # parent @@ -839,10 +706,7 @@ sub do_updates { print scalar localtime, " - Polling for updates for $username" if &debug; my $tweets; - eval { - $tweets = $obj->friends_timeline( - { since => HTTP::Date::time2str($last_poll) } ); - }; + eval { $tweets = $obj->friends_timeline(); }; if ($@) { print $fh @@ -885,6 +749,12 @@ sub do_updates { printf $fh "id:%d account:%s nick:%s type:tweet %s\n", $context->{id}, $username, $context->{user}{screen_name}, $ctext; + if ($context->{truncated}) { + printf $fh "id:%s account:%s nick:%s type:ellispis %s\n", + $context->{id}."-url", $username, + $context->{user}{screen_name}, + "http://twitter.com/$context->{user}{screen_name}/status/$context->{id}"; + } $reply = "reply"; } elsif ($@) { print $fh "type:debug request to get context failed: $@"; @@ -899,6 +769,12 @@ sub do_updates { and not Irssi::settings_get_bool("show_own_tweets"); printf $fh "id:%d account:%s nick:%s type:%s %s\n", $t->{id}, $username, $t->{user}{screen_name}, $reply, $text; + if ($t->{truncated}) { + printf $fh "id:%s account:%s nick:%s type:ellispis %s\n", + $t->{id}."-url", $username, + $t->{user}{screen_name}, + "http://twitter.com/$t->{user}{screen_name}/status/$t->{id}"; + } } print scalar localtime, " - Polling for replies" if &debug; @@ -920,6 +796,12 @@ sub do_updates { $text = &hilight($text); printf $fh "id:%d account:%s nick:%s type:tweet %s\n", $t->{id}, $username, $t->{user}{screen_name}, $text; + if ($t->{truncated}) { + printf $fh "id:%s account:%s nick:%s type:ellispis %s\n", + $t->{id}."-url", $username, + $t->{user}{screen_name}, + "http://twitter.com/$t->{user}{screen_name}/status/$t->{id}"; + } } print scalar localtime, " - Polling for DMs" if &debug; @@ -995,8 +877,15 @@ sub monitor_child { print scalar localtime, " - checking child log at $filename ($attempt)" if &debug; my $new_last_poll; + + # first time we run we don't want to print out *everything*, so we just + # pretend + my $suppress = 0; + $suppress = 1 unless keys %tweet_cache; + if ( open FILE, $filename ) { my @lines; + my %new_cache; while () { chomp; last if /^__friends__/; @@ -1009,8 +898,15 @@ sub monitor_child { } if ( not $meta{type} or $meta{type} ne 'searchid' ) { - next if exists $meta{id} and exists $tweet_cache{ $meta{id} }; - $tweet_cache{ $meta{id} } = time; + if ( exists $meta{id} and exists $new_cache{ $meta{id} } ) { + next; + } + + $new_cache{ $meta{id} } = time; + + if ( exists $meta{id} and exists $tweet_cache{ $meta{id} } ) { + next; + } } my $account = ""; @@ -1045,6 +941,12 @@ sub monitor_child { ( MSGLEVEL_PUBLIC | $hilight ), $meta{type}, $account, $meta{nick}, $marker, $_ ]; + } elsif ( $meta{type} eq 'ellispis' ) { + push @lines, + [ + MSGLEVEL_PUBLIC, + "tweet", $account, $meta{nick}, "", $_ + ]; } elsif ( $meta{type} eq 'search' ) { push @lines, [ @@ -1052,7 +954,9 @@ sub monitor_child { $meta{type}, $account, $meta{topic}, $meta{nick}, $marker, $_ ]; - if ( $meta{id} > + if ( + exists $id_map{__searches}{ $meta{account} }{ $meta{topic} } + and $meta{id} > $id_map{__searches}{ $meta{account} }{ $meta{topic} } ) { $id_map{__searches}{ $meta{account} }{ $meta{topic} } = @@ -1066,7 +970,9 @@ sub monitor_child { ]; } elsif ( $meta{type} eq 'searchid' ) { print "Search '$meta{topic}' returned id $meta{id}" if &debug; - if ( $meta{id} >= + if ( + exists $id_map{__searches}{ $meta{account} }{ $meta{topic} } + and $meta{id} >= $id_map{__searches}{ $meta{account} }{ $meta{topic} } ) { $id_map{__searches}{ $meta{account} }{ $meta{topic} } = @@ -1095,12 +1001,16 @@ sub monitor_child { if ($new_last_poll) { print "new last_poll = $new_last_poll" if &debug; - for my $line (@lines) { - $window->printformat( - $line->[0], - "twirssi_" . $line->[1], - @$line[ 2 .. $#$line ] - ); + if ($suppress) { + print "First call, not printing updates" if &debug; + } else { + foreach my $line (@lines) { + $window->printformat( + $line->[0], + "twirssi_" . $line->[1], + @$line[ 2 .. $#$line ] + ); + } } close FILE; @@ -1108,9 +1018,13 @@ sub monitor_child { or warn "Failed to remove $filename: $!" unless &debug; + # commit the pending cache lines to the actual cache, now that + # we've printed our output + %tweet_cache = ( %tweet_cache, %new_cache ); + # keep enough cached tweets, to make sure we don't show duplicates. foreach ( keys %tweet_cache ) { - next if $tweet_cache{$_} >= $last_poll; + next if $tweet_cache{$_} >= $last_poll - 3600; delete $tweet_cache{$_}; } $last_poll = $new_last_poll; @@ -1124,9 +1038,10 @@ sub monitor_child { print JSON JSON::Any->objToJson( \%id_map ); close JSON; } else { - ¬ice("Failed to write replies to $file: $!"); + &ccrap("Failed to write replies to $file: $!"); } } + $failwhale = 0; return; } } @@ -1149,7 +1064,24 @@ sub monitor_child { } else { $since = scalar localtime($last_poll); } - ¬ice("Haven't been able to get updated tweets since $since"); + + if ( not $failwhale and time - $last_poll > 60 * 60 ) { + foreach my $whale ( + q{ v v v}, + q{ | | v | v}, + q{ | .-, | | |}, + q{ .--./ / | _.---.| }, + q{ '-. (__..-" \\}, + q{ \\ a |}, + q{ ',.__. ,__.-'/}, + q{ '--/_.'----'`} + ) + { + &ccrap($whale); + } + $failwhale = 1; + } + &ccrap("Haven't been able to get updated tweets since $since"); } } @@ -1161,6 +1093,10 @@ sub notice { $window->print( "%R***%n @_", MSGLEVEL_PUBLIC ); } +sub ccrap { + $window->print( "%R***%n @_", MSGLEVEL_CLIENTCRAP ); +} + sub update_away { my $data = shift; @@ -1174,7 +1110,7 @@ sub update_away { $server->send_raw("away :$data"); return 1; } else { - ¬ice( "Can't find bitlbee server.", + &ccrap( "Can't find bitlbee server.", "Update bitlbee_server or disable tweet_to_away" ); return 0; } @@ -1227,8 +1163,10 @@ sub sig_complete { ) { # /twitter_reply gets a nick:num $word =~ s/^@//; - @$complist = map { "$_:$id_map{__indexes}{$_}" } grep /^\Q$word/i, - sort keys %{ $id_map{__indexes} }; + @$complist = map { "$_:$id_map{__indexes}{$_}" } + sort {$nicks{$b} <=> $nicks{$a}} + grep /^\Q$word/i, + keys %{ $id_map{__indexes} }; } # /tweet, /tweet_as, /dm, /dm_as - complete @nicks (and nicks as the first @@ -1303,6 +1241,7 @@ Irssi::settings_add_str( "twirssi", "twirssi_replies_store", ".irssi/scripts/twirssi.json" ); Irssi::settings_add_str( "twirssi", "twirssi_nick_color", "%B" ); Irssi::settings_add_str( "twirssi", "twirssi_topic_color", "%r" ); +Irssi::settings_add_bool( "twirssi", "twirssi_upgrade_beta", 0 ); Irssi::settings_add_bool( "twirssi", "tweet_to_away", 0 ); Irssi::settings_add_bool( "twirssi", "show_reply_context", 0 ); Irssi::settings_add_bool( "twirssi", "show_own_tweets", 1 ); @@ -1318,6 +1257,10 @@ Irssi::settings_add_bool( "twirssi", "tweet_window_input", 0 ); $last_poll = time - &get_poll_time; $window = Irssi::window_find_name( Irssi::settings_get_str('twitter_window') ); if ( !$window ) { + Irssi::active_win() + ->print( "Couldn't find a window named '" + . Irssi::settings_get_str('twitter_window') + . "', trying to create it." ); $window = Irssi::Windowitem::window_create( Irssi::settings_get_str('twitter_window'), 1 ); @@ -1328,22 +1271,14 @@ if ($window) { Irssi::command_bind( "dm", "cmd_direct" ); Irssi::command_bind( "dm_as", "cmd_direct_as" ); Irssi::command_bind( "tweet", "cmd_tweet" ); - Irssi::command_bind( "dent", "cmd_tweet" ); Irssi::command_bind( "tweet_as", "cmd_tweet_as" ); - Irssi::command_bind( "dent_as", "cmd_tweet_as" ); Irssi::command_bind( "twitter_reply", "cmd_reply" ); - Irssi::command_bind( "identica_reply", "cmd_reply" ); Irssi::command_bind( "twitter_reply_as", "cmd_reply_as" ); - Irssi::command_bind( "identica_reply_as", "cmd_reply_as" ); - Irssi::command_bind( "twitter_login", "cmd_login_twitter" ); - Irssi::command_bind( "twitter_logout", "cmd_logout_twitter" ); - Irssi::command_bind( "identica_login", "cmd_login_identica" ); - Irssi::command_bind( "identica_logout", "cmd_logout_identica" ); + Irssi::command_bind( "twitter_login", "cmd_login" ); + Irssi::command_bind( "twitter_logout", "cmd_logout" ); Irssi::command_bind( "twitter_switch", "cmd_switch" ); - Irssi::command_bind( "twitter_subscribe", "cmd_add_search_twitter" ); - Irssi::command_bind( "identica_subscribe", "cmd_add_search_identica" ); - Irssi::command_bind( "twitter_unsubscribe", "cmd_del_search_twitter" ); - Irssi::command_bind( "identica_unsubscribe", "cmd_del_search_identica" ); + Irssi::command_bind( "twitter_subscribe", "cmd_add_search" ); + Irssi::command_bind( "twitter_unsubscribe", "cmd_del_search" ); Irssi::command_bind( "twitter_list_subscriptions", "cmd_list_search" ); Irssi::command_bind( "twirssi_upgrade", "cmd_upgrade" ); if ( Irssi::settings_get_bool("twirssi_use_reply_aliases") ) { @@ -1359,14 +1294,18 @@ if ($window) { print "nicks: ", join ", ", sort keys %nicks; print "searches: ", Dumper \%{ $id_map{__searches} }; print "last poll: $last_poll"; + if ( open DUMP, ">/tmp/twirssi.cache.txt" ) { + print DUMP Dumper \%tweet_cache; + close DUMP; + print "cache written out to /tmp/twirssi.cache.txt"; + } } ); Irssi::command_bind( "twirssi_version", sub { ¬ice("Twirssi v$VERSION (r$REV); " - . "Net::Identica v$Net::Identica::VERSION. " - . "Net::Twitter v$Net::Twitter::VERSION." + . "Net::Twitter v$Net::Twitter::VERSION. " . "JSON in use: " . JSON::Any::handler() . ". See details at http://twirssi.com/" ); @@ -1394,7 +1333,7 @@ if ($window) { ¬ice(" %Y<%C(%B^%C)%N TWIRSSI v%R$VERSION%N (r$REV)"); ¬ice(" %C(_(\\%N http://twirssi.com/ for full docs"); ¬ice( - " %Y||%C `%N Log in with /twitter_login or /identica_login, send updates with /tweet or /dent"); + " %Y||%C `%N Log in with /twitter_login, send updates with /tweet"); my $file = Irssi::settings_get_str("twirssi_replies_store"); if ( $file and -r $file ) { @@ -1408,6 +1347,7 @@ if ($window) { my $num = keys %{ $id_map{__indexes} }; ¬ice( sprintf "Loaded old replies from %d contact%s.", $num, ( $num == 1 ? "" : "s" ) ); + &cmd_list_search; }; } else { ¬ice("Failed to load old replies from $file: $!"); @@ -1424,16 +1364,11 @@ if ($window) { } } - if ( my $autouser = Irssi::settings_get_str("twitter_usernames_twitter") - and my $autopass = Irssi::settings_get_str("twitter_passwords_twitter") ) - { - &cmd_login_twitter(); - } - - if ( my $autouser = Irssi::settings_get_str("twitter_usernames_identica") - and my $autopass = Irssi::settings_get_str("twitter_passwords_identica") ) + if ( my $autouser = Irssi::settings_get_str("twitter_usernames") + and my $autopass = Irssi::settings_get_str("twitter_passwords") ) { - &cmd_login_identica(); + &cmd_login(); + &get_updates; } } else { @@ -1441,4 +1376,6 @@ if ($window) { ->print( "Create a window named " . Irssi::settings_get_str('twitter_window') . " or change the value of twitter_window. Then, reload twirssi." ); -} \ No newline at end of file +} + +# vim: set sts=4 expandtab: