stMind

about Tech, Computer vision and Machine learning

instagram→twitter→mixiフォトで写真をもっと共有する!

instagramって写真撮影をすごくカジュアルにしてくれた素晴らしいサービスだと思っていて、instagramの写真をmixiでも共有したい!ということでスクリプトを書いてみました。
実は、最初はinstagramの非公開APIを使ったスクリプトを書いていたんですが、自分の写真がFetchできなく(404が返ってくるように)なってしまったので、twitterを経由してmixiフォトにアップロードすることにしました。

やっていること

大きく分けて以下の3つです。

  1. 一日分のツイートからhttp://instagr.am/*のURLを取り出す
    • mixiフォトへのアップロードに非公開APIを使うのであまり負荷をかけないよう、一日分のツイートをまとめて一日一回処理することを想定
    • ただ、一日前の時刻から最大200件までが対象なので実質は一日とは言えない・・・
  2. http://instagr.am/*スクレイピングして写真をダウンロード
    • 600x600以上ならImage::Magickで半分にリサイズ
  3. mixiフォトにアップロード
    • アップロード先のアルバムはinstagramという名前で事前に作成

後はcronを使って一日一回スクリプトを実行するようにしています。

スクリプト

ソースは以下の通りです。gist: 755514 - GitHubでも公開してます。

#!perl

use strict;
use warnings;

use URI;
use Web::Scraper;
use Net::Twitter;
use Config::Pit;
use DateTime;
use Encode qw(encode_utf8);
use File::Basename;
use File::Slurp;
use XML::Simple;
use Image::Magick;

#### ツイートを取得 ##############################

my $config = pit_get("twitter.com", require => {
    "username" => "your username on twitter.com",
    "consumer_key" => "your consumer_key on twitter.com",
    "consumer_secret" => "your consumer_secret on twitter.com",
    "access_token" => "your access_token on twitter.com",
    "access_token_secret" => "your token_secret on twitter.com"
});

my $nt = Net::Twitter->new(
    traits => [qw/OAuth API::REST/],
    consumer_key => $config->{consumer_key},
    consumer_secret => $config->{consumer_secret},
    access_token => $config->{access_token},
    access_token_secret => $config->{access_token_secret},
);

my $dt = DateTime->now( time_zone => 'Asia/Tokyo' );
$dt->subtract( days => 1 );

my $statuses = $nt->user_timeline({ since => $dt,
                                    count => '200',
                                    id => $config->{username} });

my @urls;
for my $status (@$statuses) {
    if( $status->{text} =~ /(http:\/\/instagr.am\/.+)/ ) {
        push(@urls, $1);
    }
}

if( @urls == 0 ) { 
    print "No new upload image to instagr.am\n";
    exit(0);
}

#### インスタグラムのページをスクレイピング ##############

my @photos;

print "### Download Photos ###\n";
for my $url (@urls) {

    my $instagram = scraper {
        process ".photo", link => '@src';
    };

    my $res = $instagram->scrape(URI->new($url));

    # ファイルをダウンロードする
    my $ua = LWP::UserAgent->new;
    my $file = basename($res->{link});
    if( -e $file ) {
        print "Download skip : $file\n";
    }
    else {
        $ua->mirror($res->{link}, $file);
        print "Downloaded : $file\n";
        push(@photos, $file);
    }
}

# リサイズ
my @r_photos;
my $th_x = 600;
my $th_y = 600;
my $im = Image::Magick->new;
for my $photo (@photos) {
    $im->Read($photo);
    my ($x, $y) = $im->Get('width', 'height');
    if( $x >= $th_x && $y >= $th_y ) {
        $im->Resize( width => $x / 2, height => $y / 2 );
        $im->Write( filename => "r_$photo" );
        push(@r_photos, "r_$photo");
    }
    else {
        push(@r_photos, $photo);
    }
}

###### mixiに画像をアップロード #######################

my $config2 = pit_get("mixi.jp", require => {
    "mailaddress" => "your mailaddress on mixi.jp",
    "password" => "your password on mixi.jp"
});

my $ua2 = LWP::UserAgent->new;
$ua2->credentials('photo.mixi.jp:80', '',
                 $config2->{mailaddress},
                 $config2->{password});

my $res2 = $ua2->get('http://photo.mixi.jp/atom/r=3');
die "Album Info can't get... : $res2->status_line\n" if $res2->is_error;

## アップロードするアルバムIDを取得
## 事前に'instagram'というアルバムを作成しておく
my $ref2 = XMLin($res2->content);
my $href;
my $title;
foreach my $c (@{$ref2->{workspace}->{collection}}) {
    $title = encode_utf8($c->{'atom:title'});

    if( ($title eq 'instagram') && ($c->{accept} eq 'image/jpeg') ) {
        $href = $c->{href};
    }
}
die "Album not found...\n" . $title unless defined($href);

## 画像をアップロード
print "### Upload Photos ###\n";
foreach my $r_image (@r_photos) {
    # アップロードするファイル
    my $f = read_file($r_image, binmode => ":raw");

    my $r = $ua2->post($href,
                       'Content-Type' => 'image/jpeg',
                       'content' => join "", $f);

    if( $r->is_success ) {
        print "Upload done! : $r_image\n";
    }
    else {
        print "Upload failed... : $r_image\;n";
    }
}

その他

今のinstagramはシャレオツな写真が多くて、もっとバカバカしい写真が増えてくるといいなぁとか思っています。iPhoneをお持ちの方はぜひアプリをインストールして試していただけるといいかと思います!