#! /usr/bin/perl use strict; use warnings; use LWP::RobotUA; use Data::Dumper; use ExtUtils::MakeMaker 'prompt'; use IPC::Cmd qw(can_run run); my $username = prompt('Username:'); my $password = prompt('Password:'); my $ua = do { my $ua = LWP::RobotUA->new('ust-dl-bot-0.1', 'seijro@gmail.com'); $ua->delay(2/60); $ua->cookie_jar({}); $ua; }; my $xpath = $ua->_::req('http://www.ustream.tv/login'); my $form_elm = $xpath->findnodes('id("MScontent")/*[.="Login"]/following-sibling::form[1]')->pop; my $form_hash = do { my $form_hash = { map { $_->attr('name') ? ($_->attr('name'), $_->attr('value')) : (); } $form_elm->findnodes('.//input')->get_nodelist }; $form_hash->{'login[username]'} = $username; $form_hash->{'login[password]'} = $password; $form_hash; }; $ua->_::req($form_elm->attr('action'), $form_hash); my $video_list = do { my $_list = []; my $_page_counter = 1; my $_callee; $_callee = sub { $xpath = $ua->_::req("http://www.ustream.tv/myvideos/newest_first/$_page_counter", $form_hash); my @list = $xpath->findnodes('//div[@class="item"]')->get_nodelist; return $_list if (@list == 0); $_list = [ @$_list, map { [ $_->findnodes('./descendant::a[1]')->pop->attr('title'), $_->findnodes('./descendant::a[2]')->pop->attr('href'), ] } @list ]; $_page_counter++; &$_callee; }; }->(); while (1) { my $prompt = prompt('command >'); next unless ($prompt); my @args = split(' ', $prompt); my $command = shift @args; if ($command eq 'q' or $command eq 'quit' or $command eq 'exit') { last; } elsif ($command eq 'list') { for (my $i = 0; $i < @$video_list; $i++) { printf "%2d %s\n", $i, $video_list->[$i][0]; } print "" } elsif ($command eq 'get') { for my $index (@args) { my ($name, $url) = @{ $video_list->[$index] }; $name =~ s/\s+/_/g; $xpath = $ua->_::req($url); $url = $xpath->findnodes('//a[. = ".FLV"]')->pop->attr('href'); $ua->_::req($url, undef, "${index}_${name}_ust.flv"); } } elsif ($command eq 'ust2smile') { for my $index (@args) { my ($name, $url) = @{ $video_list->[$index] }; $name =~ s/\s+/_/g; my $ust_file_name = "${index}_${name}_ust.flv"; my $smile_file_name = "${index}_${name}_smile.flv"; $xpath = $ua->_::req($url); $url = $xpath->findnodes('//a[. = ".FLV"]')->pop->attr('href'); $ua->_::req($url, undef, $ust_file_name); if (can_run('ffmpeg')) { my $captured; run(command => "ffmpeg -i $ust_file_name -y -b 250k -r 10 -vcodec flv -s 512x384 -acodec libmp3lame -ab 32 -ac 1 -async 1 $smile_file_name", buffer => \$captured, verbose => 1) or die "Command failed: $captured"; } else { die "This tool need ffmpeg command!"; } } } } package _; use Data::Dumper; use HTML::TreeBuilder::XPath; use IPC::Cmd qw(can_run run); sub req { my ($ua, $url, $hash, $filename) = @_; $url =~ s#^(?=/)#http://www.ustream.tv#; $url =~ s#^\s+|\s+$##g; if ($filename) { if (can_run('wget')) { local $| = 1; print "Downloading <$url>\n"; my $session_key = $ua->cookie_jar->{COOKIES}->{'www.ustream.tv'}->{'/'}->{PHPSESSID}->[1]; my $cmd = "wget --no-cookies --header \"Cookie: PHPSESSID=$session_key\" $url -O $filename"; my $captured; run(command => $cmd, buffer => \$captured, verbose => 1) or die "Command failed: $captured"; } else { die "This tool need wget command!"; } } else { print "Requesting <$url> ... "; my $res = $hash ? $ua->post($url, $hash) : $ua->get($url); my $x = HTML::TreeBuilder::XPath->new; $x->parse($res->content); print $res->message . ' [' . $res->code . "]\n"; return $x; } }