Subscribed unsubscribe Subscribe Subscribe

TerminalでTwitterとWassr 機能追加

Net::Twissrを使ってターミナルでTwitter&Wassr - すぎゃーんメモ から機能追加。
リスト表示<->詳細表示を切り替えられるように。
投稿もできるようになった。…はず。
自分の環境でしか試してないけど。

#!/usr/bin/perl
use strict;
use warnings;

use Config::Pit;
use HTTP::Date;
use Jcode;
use Net::Twissr;
use Switch;
use Term::Screen;

my $config = Config::Pit::get('twissr', require => {
    'twitter_username' => 'your username on twitter.com',
    'twitter_password' => 'your password on twitter.com',
    'wassr_username' => 'your username on wassr.jp',
    'wassr_password' => 'your password on wassr.jp',
});
my $twissr = Net::Twissr->new($config);

my ($rows, $cols);
my $screen = new Term::Screen;
$rows = $screen->rows();
$cols = $screen->cols();

my @friends_timeline;
&refresh_friends_timeline(\@friends_timeline);

# --- usage ---
# k: up
# j: down
# h: detail
# l: list
# r: refresh
# q: quit
# p: post

my $mode = 0;
my $index = 0;
my $offset = 0;

&draw(\@friends_timeline, $mode, $index, $offset);
MAIN: while (1) {
    while (1) {
        my $ch = undef;
        my $getch = new Term::Screen;
        $ch = $getch->noecho()->at($rows, $cols)->getch();
        last MAIN unless (defined $ch);
        last MAIN if ($ch eq 'q');
        if ($ch eq 'k') {
            $index-- if ($index > 0);
            $offset-- if ($index - $offset < 0);
        }
        if ($ch eq 'j') {
            $index++ if ($index < $#friends_timeline);
            $offset++ if ($index - $offset > $rows - 1);
        }
        if ($ch eq 'h') {
            $mode = 1;
        }
        if ($ch eq 'l') {
            $mode = 0;
        }
        if ($ch eq 'r') {
            &refresh_friends_timeline(\@friends_timeline);
        }
        if ($ch eq 'p') {
            $screen->clrscr()->at(0, 0)->puts('Message:')->at(1, 0);
            last;
        }
        &draw(\@friends_timeline, $mode, $index, $offset);
    }

    my $status = <>;
    if (defined $status) {
        chomp($status);
        &update($status);
    }
    &draw(\@friends_timeline, $mode, $index, $offset);
}

# 終了処理
$screen->normal()->clrscr();

# Terminalへの描画
sub draw {
    my ($timeline, $mode, $index, $offset) = @_;
    $screen->clrscr();
    switch ($mode) {
        case 0 {
            for (0..$rows - 1) {
                last if ($_ > @$timeline - 1);
                # 選択している行を反転表示
                $screen->reverse() if ($_ + $offset == $index);
                my $status = $timeline->[$_ + $offset];
                $screen->at($_, 0)->puts($status->{line})->clreol()->normal();
            }
        };
        case 1 {
            my $row = 0;
            my $status = $timeline->[$index];
            $screen->at($row++, 0)->puts($status->{service})->clreol();
            return if ($row > $rows - 1);
            $screen->at($row++, 0)->puts(scalar(localtime($status->{time})))->clreol();
            return if ($row > $rows - 1);
            my $user = (Jcode->new($status->{user_id} . ' / ' . $status->{user_name})->jfold($cols))[0];
            $screen->at($row++, 0)->puts($user)->clreol();
            return if ($row > $rows - 1);
            my @text = Jcode->new($status->{text})->jfold($cols - 1);
            for (0..$#text) {
                $screen->at($row++, 0)->puts($text[$_])->clreol();
                return if ($row > $rows - 1);
            }
        };
    }
    $screen->at($rows, 0);
}

# friends_timelineの更新
sub refresh_friends_timeline {
    my $timeline = shift;
    my $friends_timeline = $twissr->friends_timeline();
    TIMELINE: for (@$friends_timeline) {
        for my $status (@$timeline) {
            if ($_->{service} eq $status->{service} && $_->{id} eq $status->{id}) {
                next TIMELINE;
            }
        }
        my $time = HTTP::Date::time2iso($_->{time});
        my $service = substr($_->{service}, 0, 1);
        my $line = qq/[$time] ($service) $_->{user_id} : $_->{text}/;
        # 1行分の長さに切る
        $line = (Jcode->new($line)->jfold($cols))[0];
        $_->{line} = $line;
        push @$timeline, $_;
    }

    @$timeline = sort { $b->{time} <=> $a->{time} } @$timeline;
}

# statusの更新
sub update {
    my $status = shift;
    $twissr->update($status);
}

Term::Screenでgetchを呼び出した後でreadlineさせようとするとおかしくなってしまったので、getchするところだけは別のインスタンスで処理。
readlineのときに途中でCtrl-Dを2回押すと、STDINからの読み込みがundefで繰り返されてしまってプログラムが続行不能になってしまう…どうすればいいんだろう
/lang/perl/Net-Twissr/trunk/example/terminal.pl – CodeRepos::Share – Trac