Just finished a script, that enables me or anyone else who cares to send tweets directly to a IRC-Channel. The script is powered by the best IRC-Client ever made, perl, and Net::Twitter::Lite.

  • Update [2023-08-18]: Nobody should use twitter or perl or irc any more ;)
  • Update [2013-06-15]: upgrade to Net::Twitter::Lite::WithAPIv1_1
  • Update [2013-01-12]: second update today added the setting “_count” and some cleanups with vars and setup
  • Update [2013-01-12]: drastically reduced the amout of requests to the API

P.S.: you can also follow me on twitter, but beware that almost half of my tweets will be neither about programming nor in english ;-). Follow @matschundbrei, if you don’t care!

use strict;
use warnings;
use Irssi;
use Irssi::Irc;
use Net::Twitter::Lite::WithAPIv1_1;
use Scalar::Util 'blessed';

our $VERSION = '42.06';
our %IRSSI   = (
    authors => 'Jan Kapellen',
    contact => 'jkapellen@gmail.com',
    name    => 'irtweet',
    description =>
'Send tweets from one or more twitter accounts to a channel of your choice',
    license => 'Beerware',
);

#to add accounds (beside your account) use /set irtweet_additional_users foo[,bar,bla,me]
#my twitter api settings, you can change them if you like
our $twitter = Net::Twitter::Lite::WithAPIv1_1->new(
    consumer_key    => 'iXywdwhdvjG3Orfj01M0Tg',
    consumer_secret => 'xBc2cmfegJakirKsdZJY3QimkcmPFZnjwiS1TYZyc0',
    clientname      => 'irtweet',
    clientver       => '0.0.0.1',
    ssl             => 1,
);

# Register formats
Irssi::theme_register(
    [ 'irtweet_crap', '{line_start}{hilight ' . $IRSSI{'name'} . ':} $0' ] );

#irssi vars:
#timeout in seconds between each call to the twitter api
#by twitter: 350/h max = not much more than 2 per minute ~ min timeout = 30!!
#remember you're doing at least two requests, each time
Irssi::settings_add_int( 'misc', $IRSSI{'name'} . "_timeout", 60 );

#count of tweets to be grabbed from your home_timeline
Irssi::settings_add_int( 'misc', $IRSSI{'name'} . "_count", 100 );

#can set the script to inactive if needed:
Irssi::settings_add_bool( 'misc', $IRSSI{'name'} . "_active", 1 );
Irssi::settings_add_str( 'misc', $IRSSI{'name'} . "_access_token",        "" );
Irssi::settings_add_str( 'misc', $IRSSI{'name'} . "_access_token_secret", "" );
Irssi::settings_add_str( 'misc', $IRSSI{'name'} . "_last",                "0" );
Irssi::settings_add_str( 'misc', $IRSSI{'name'} . "_additional_users",    "" );
Irssi::settings_add_str( 'misc', $IRSSI{'name'} . "_target_channels",     "" );
Irssi::settings_add_str(
    'misc',
    $IRSSI{'name'} . "_msg_txt",
    "live from the timeline of @"
);
Irssi::settings_add_str( 'misc', $IRSSI{'name'} . "_pin",         "" );
Irssi::settings_add_str( 'misc', $IRSSI{'name'} . "_user_id",     "" );
Irssi::settings_add_str( 'misc', $IRSSI{'name'} . "_screen_name", "" );

my $tag = undef;

my $mill = Irssi::settings_get_int( $IRSSI{'name'} . "_timeout" );
if ( $mill < 30 ) {
    Irssi::settings_set_int( $IRSSI{'name'} . "_timeout", 30 );
    Irssi::printformat( MSGLEVEL_CLIENTCRAP, "irtweet_crap",
        "the minimum timeout for fetching new tweets is 30 seconds!" );
    $mill = 30000;
}
else { $mill = $mill * 1000; }

tweet();

Irssi::timeout_remove($tag) if $tag;

$tag = Irssi::timeout_add( $mill, 'tweet', undef );

if ( Irssi::settings_get_bool( $IRSSI{'name'} . "_active" ) == 0 ) {
    Irssi::timeout_remove($tag);
}

#main subroutine, this is what tweets ;)
sub tweet {
    if (
        length( Irssi::settings_get_str( $IRSSI{'name'} . "_access_token" ) ) >
        0
        && length(
            Irssi::settings_get_str( $IRSSI{'name'} . "_access_token_secret" )
        ) > 0
      )
    {
        $twitter->access_token(
            Irssi::settings_get_str( $IRSSI{'name'} . "_access_token" ) );
        $twitter->access_token_secret(
            Irssi::settings_get_str( $IRSSI{'name'} . "_access_token_secret" )
        );
    }

    unless ( $twitter->authorized ) {
        Irssi::command_bind( 'twitterpin', 'cmd_pin' );
        getAuthParam();
        $twitter->access_token(
            Irssi::settings_get_str( $IRSSI{'name'} . "_access_token" ) );
        $twitter->access_token_secret(
            Irssi::settings_get_str( $IRSSI{'name'} . "_access_token_secret" )
        );
        return 0;
    }

    unless (
        length(
            Irssi::settings_get_str( $IRSSI{'name'} . "_target_channels" )
        ) > 0
      )
    {
        Irssi::printformat( MSGLEVEL_CLIENTCRAP, "irtweet_crap",
            "please set the target channels to tweet to with:" );
        Irssi::printformat( MSGLEVEL_CLIENTCRAP, "irtweet_crap",
            "/set " . $IRSSI{'name'} . "_target_channels #foo[,#bar]" );
        return 0;
    }
    my @chantemp =
      split( ',',
        Irssi::settings_get_str( $IRSSI{'name'} . "_target_channels" ) );
    my @channel;
    foreach (@chantemp) {
        my $chan = Irssi::channel_find($_);
        if ( ( $chan->{'joined'} ) == 1 ) { push( @channel, $_ ); }
        else {
            Irssi::printformat( MSGLEVEL_CLIENTCRAP, "irtweet_crap",
                "sorry, but it seems you have not joined any channel named"
                  . $_ );
        }
    }

    #now we got all the channels, time for some tweets, finally!
    our @users;
    push( @users, Irssi::settings_get_str( $IRSSI{'name'} . "_screen_name" ) );
    if (
        length(
            Irssi::settings_get_str( $IRSSI{'name'} . "_additional_users" )
        ) > 0
      )
    {
        my @tmp =
          split( ',',
            Irssi::settings_get_str( $IRSSI{'name'} . "_additional_users" ) );
        foreach (@tmp) { push( @users, $_ ); }
    }
    our %timelineitems;    #key = user, value = scalar/messages
    our $last = Irssi::settings_get_str( $IRSSI{'name'} . "_last" );
    our $max  = 0;
    eval {
        my %twitbuds;
        foreach (@users) { $twitbuds{$_} = 1; }
        my $msgs;          #contains the full timeline map for user
        my $count = Irssi::settings_get_int( $IRSSI{'name'} . "_count" );
        if ( $last > 0 ) {
            $msgs = $twitter->home_timeline(
                {
                    since_id           => $last,
                    include_rts        => 1,
                    include_my_retweet => 1,
                    count              => $count,
                }
            );
        }
        else {
            $msgs = $twitter->home_timeline(
                { count => $count, include_rts => 1, include_my_retweet => 1, }
            );
        }
        foreach my $status (@$msgs) {
            my $screenname = $status->{'user'}->{'screen_name'};
            if ( $twitbuds{$screenname} ) {

                #debug
                #Irssi::print( $status->{'id'} );
                if ( $status->{'id'} > $last ) {
                    push( @{ $timelineitems{$screenname} }, $status->{'text'} );
                }
                if ( $status->{'id'} > $max ) {
                    $max = $status->{'id'};
                }
            }
        }
    };

    #new stuff out of Net::Twitter::Lite::WithAPIv1_1
    if ( my $err = $@ ) {
        die $@ unless blessed $err && $err->isa('Net::Twitter::Lite::Error');

        warn "irtweet: Twitter API error: ", $err->error, "\n";
    }
    if ( $max != 0 ) {
        Irssi::settings_set_str( $IRSSI{'name'} . "_last", $max );
    }

    #consume messages:
    foreach my $channel (@channel) {
        my $chanObj = Irssi::channel_find($channel);
        foreach my $user ( keys %timelineitems ) {
            my @messages = @{ $timelineitems{$user} };
            foreach my $msg (@messages) {

          #debug
          #Irssi::print("to channel:".$channel."with user ".$user." msg:".$msg);
                $chanObj->{server}->command( "MSG " 
                      . $channel . " "
                      . Irssi::settings_get_str( $IRSSI{'name'} . "_msg_txt" )
                      . $user . ": "
                      . $msg );
            }
            delete $timelineitems{$user};
        }
    }

}

sub getAuthParam {
    my $pin = Irssi::settings_get_str( $IRSSI{'name'} . "_pin" );
    unless ( length($pin) > 0 ) {
        Irssi::printformat( MSGLEVEL_CLIENTCRAP, "irtweet_crap",
            "You will have to authorize the twitter Access!" );
        Irssi::printformat( MSGLEVEL_CLIENTCRAP, "irtweet_crap",
            "please go to:" . $twitter->get_authorization_url );
        Irssi::printformat( MSGLEVEL_CLIENTCRAP, "irtweet_crap",
            "and enter the displayed pin with \"/twitterpin <yourpin>\"" );
    }
    return 0;
}

sub cmd_pin {
    my ( $pin, $server, $win ) = @_;
    my ( $access_token, $access_token_secret, $user_id, $screen_name ) =
      $twitter->request_access_token( verifier => $pin );
    Irssi::settings_set_str( $IRSSI{'name'} . "_access_token", $access_token );
    Irssi::printformat( MSGLEVEL_CLIENTCRAP, "irtweet_crap",
        "access token set to " . $access_token );
    Irssi::settings_set_str( $IRSSI{'name'} . "_access_token_secret",
        $access_token_secret );
    Irssi::printformat( MSGLEVEL_CLIENTCRAP, "irtweet_crap",
        "access token set to " . $access_token_secret );
    Irssi::settings_set_str( $IRSSI{'name'} . "_user_id", $user_id );
    Irssi::printformat( MSGLEVEL_CLIENTCRAP, "irtweet_crap",
        "user id set to " . $user_id );
    Irssi::settings_set_str( $IRSSI{'name'} . "_screen_name", $screen_name );
    Irssi::printformat( MSGLEVEL_CLIENTCRAP, "irtweet_crap",
        "screen name set to " . $screen_name );
    return 0;
}