読者です 読者をやめる 読者になる 読者になる

Flickrから最新の写真をダウンロード

Flickrで写真を眺めるのが日課の今日この頃です。

お気に入りの写真をiPod touchにいれて持ち歩くために、ダウンロードするためのスクリプトを書いていました。お気に入りの人の写真のフィードのURLを与えて、それらのフィード中の写真を一括でダウンロードするようにしています。

#!/usr/bin/env perl
use strict;
use warnings;
use Carp qw/croak/;
use URI;
use URI::Fetch;
use XML::RSS::LibXML;
use Path::Class qw(dir);
use Perl6::Say;
use IO::All;
use HTTP::Async;
use HTTP::Request;
use Digest::MD5 qw(md5_hex);

our @photo_feed_urls
    = (
    'http://api.flickr.com/services/feeds/photos_public.gne?id=21183222@N07&lang=en-us&format=rss_200',
    );

main();

sub main {
    for my $feed_url (@photo_feed_urls) {
        download_photos_from_feed($feed_url);
    }
}

sub download_photos_from_feed {
    my $feed_url   = shift;
    my $rss        = parse_rss($feed_url);
    my $photo_urls = extract_photo_urls($rss);
    fetch_photos($photo_urls);
}

sub parse_rss {
    my $url = shift;
    my $uri = URI->new($url);
    my $res = URI::Fetch->fetch($uri)
        or croak sprintf "%s (%s)", URI::Fetch->errstr, $uri;
    my $rss = XML::RSS::LibXML->new;
    $rss->parse( $res->content );
    $rss;
}

sub extract_photo_urls {
    my $rss  = shift;
    my @urls = ();
    for my $item ( @{ $rss->{items} } ) {
        my $media = $item->{media}->{content}
            or die "RSS should have media:content element";
        push @urls, $media->{url};
    }
    \@urls;
}

sub fetch_photos {
    my $urls = shift;
    my $async = HTTP::Async->new;

    my $photos_map = {};
    foreach my $url ( @{$urls} ) {
        my $id = $async->add( HTTP::Request->new( GET => $url ) );
        $photos_map->{$id} = $url;
    }

    while ( my ( $response, $id ) = $async->wait_for_next_response ) {
        say "Downloading...: " . $photos_map->{$id};
        if ( $response->is_success ) {
            eval {
                my $photo_name = md5_hex( $photos_map->{$id} );
                my $out = io( $photo_name . ".jpg" ) or die $!;
                $out->print( $response->content );
                $out->close;
            };
        }
    }
}

__END__