#!/usr/bin/perl #--------------------------------------------------------------------- # twitter API を用いprofile icon および backgroundの変更を行う # # version : 0.01 # created : 2011/08/16 KOBAYASHI Jun. # modified : # # memo : icon 変更後は tweetならびに背景の変更などアクションが # : あるまでiconは変更されない(twitterの仕様) #--------------------------------------------------------------------- # # 感謝 # # http://www.magicvox.net/ --> ほとんどソースを使用しました。 # http://nabe.blog.abk.nu/ --> base64encode ルーチンを使用しました。 # # # packages. # use strict; # hetemlのcronに登録する場合 配置先ディレクトリを # 追加しておく必要がある BEGIN { unshift(@INC,"./tool"); } use Digest::HMAC_SHA1; use HTTP::Request::Common; use LWP::UserAgent; # # constant # use constant { REQUEST_METHOD => 'POST', CONSUMER_KEY => 'xxxxxxxxxxxxxxxxxxxxxx', CONSUMER_SECRET => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', ACCESS_TOKEN => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', ACCESS_SECRET => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', }; # # argment check. # if($#ARGV < 1 or $#ARGV > 2){ &usage('argment err.'); } my $request_uri; my $tile; my $category; # API select. if($ARGV[0] eq '-i'){ $request_uri = 'http://api.twitter.com/1/account/update_profile_image.xml'; $category = 'icon'; }elsif($ARGV[0] eq '-b'){ $request_uri = 'http://api.twitter.com/1/account/update_profile_background_image.xml'; $category = 'background'; if($ARGV[2] eq 'tile'){ $tile = 'true'; } }else{ &usage('parameter err.'); } # file check. my $img_file = $ARGV[1]; if(!-e "$img_file"){ &usage('file not found.'); } # size check. my $filesize = -s "$img_file"; if($ARGV[0] eq '-i'){ if($filesize >= 700000 or $filesize == 0){ &usage('icon image size err.'); } }elsif($ARGV[0] eq '-b'){ if($filesize >= 800000 or $filesize == 0){ &usage('background image size err.'); } } # # oAuth params # my %oauth = ( oauth_consumer_key => CONSUMER_KEY, oauth_token => ACCESS_TOKEN, oauth_signature_method => 'HMAC-SHA1', oauth_timestamp => time, oauth_nonce => &generate_nonce(), oauth_version => '1.0', ); # # twitter extra params # my %param; if($tile eq 'true'){ %param = ( 'tile' => _encode_url ('true'), ); }else{ %param =(); } # # oAuth signature generate # tile を含むextra parameterは、multipart/form-dataの場合signatureに含めない # $oauth{oauth_signature} = get_signature (REQUEST_METHOD, $request_uri, %oauth); # # http request generate # # parameterにupするファイルを追加 $param{image} = ["$img_file"]; my $req = POST( $request_uri, 'Authorization' => get_oauth_header (%oauth), 'Content-Type' => 'form-data', 'Content' => [ %param ] ); # # http request(POST) # my $ua = LWP::UserAgent->new or die 'Failed to initialize LWP::UserAgent'; my $res = $ua->request($req); # # result(debug) # # print STDERR "(debug)request string:-----------------------------------------------------------------\n\n". $req->as_string."\n"; # print STDERR "(debug)content type: ". $res->content_type."\n\n"; # print STDERR "(debug)header = ". $res->headers_as_string()."\n\n"; # print STDERR "(debug)result = ". $res->status_line."\n\n"; if(! $res->is_success) { print STDERR "\nErr : $res->status_line\n"; }else{ if(defined($tile)){ print STDERR "\n change $category image : $img_file - tiled\n\n"; }else{ print STDERR "\n change $category image : $img_file\n\n"; } } exit 0; #----------------------------------------------------------------------------------------- # oauth_nonce を生成 #----------------------------------------------------------------------------------------- sub generate_nonce { my $str = &base64encode(pack 'C*', map { int rand 256 } 1..12 ); # 記号は除く $str =~ tr!+=/!012!; $str; } #----------------------------------------------------------------------------------------- # 送信するパラメータから oauth_signature を生成 #----------------------------------------------------------------------------------------- sub get_signature { my ($method, $uri, %params) = @_; my $params = join '&', map { join '=', $_, $params{$_}; } sort keys %params; my $base_string = join '&', $method, &_encode_url ($uri), &_encode_url ($params); my $key = join '&', CONSUMER_SECRET, ACCESS_SECRET; &base64encode(Digest::HMAC_SHA1::hmac_sha1 ($base_string, $key)); } #----------------------------------------------------------------------------------------- # OAuth HTTP ヘッダ(Authorize)文字列の生成する #----------------------------------------------------------------------------------------- sub get_oauth_header { my (%param) = @_; 'OAuth '. join ', ', map { sprintf '%s="%s"', $_, &_encode_url($param{$_}); } keys %param; } #----------------------------------------------------------------------------------------- # POST するデータ文字列(extra params)を生成する #----------------------------------------------------------------------------------------- sub get_content { my (%param) = @_; join '&', map { sprintf '%s=%s', $_, $param{$_}; } keys %param; } #----------------------------------------------------------------------------------------- # url encode #----------------------------------------------------------------------------------------- sub _encode_url { my ($str) = @_; $str =~ s!([^a-zA-Z0-9_.~-])!sprintf '%%%02X',ord($1)!ge; $str; } #=============================================================================== # base64 encode #=============================================================================== sub base64encode { my $str = shift; my $table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; my $ret; # 2 : 0000_0000 1111_1100 # 4 : 0000_0011 1111_0000 # 6 : 0000_1111 1100_0000 my ($i, $j, $x, $y); for($i=$x=0, $j=2; $i>$j) & 0x3f, 1); if ($j != 6) { $j+=2; next; } # j==6 $ret .= substr($table, $x & 0x3f, 1); $j = 2; } if ($j != 2) { $ret .= substr($table, ($x<<(8-$j)) & 0x3f, 1); } if ($j == 4) { $ret .= '=='; } elsif ($j == 6) { $ret .= '='; } $ret =~ s/^\s+|\s+$//g; return $ret; } #=============================================================================== # usage #=============================================================================== sub usage($) { my $msg = shift; print STDERR "\n", "twitter API / icon,background change script.\n", "usage: $0 (-i or -b) imgefile [tile] \n", "\n", " -i : profile icon change.\n", " -b : profile background change.\n", " imgfile : (-i) GIF, JPG, or PNG image of less than 700 kilobytes in size.\n", " : Images with width larger than 500 pixels will be scaled down. \n", " : Animated GIFs will be converted to a static GIF of the first frame,\n", " : removing the animation.\n", "\n", " : (-b) GIF, JPG, or PNG image of less than 800 kilobytes in size. \n", " : Images with width larger than 2048 pixels will be forcibly scaled down\n", "\n", " tile : tile is tile option use,(-b only)\n\n\n"; if(defined($msg)){ print " Err : $msg\n\n"; } exit(-1); }