#!perl -w
use strict;
# Scans my photostream to check for photos that haven't been placed into
# their correct views groups.
use Flickr::API;
use XML::Simple;
use LWP::UserAgent;
use Encode;
use Time::HiRes qw(usleep);
use FileHandle;
use Getopt::Long;
# Define these strings in apikey.ph
our ($api_key, $myid);
require "apikey.ph";
my @groups = (
{
name => "1-25 Views",
id => '66969363@N00',
lbound => 1,
ubound => 24
},
{
name => "25-50 Views",
id => '55265535@N00',
lbound => 25,
ubound => 49
},
{
name => "50-75 Views",
id => '38541060@N00',
lbound => 50,
ubound => 74
},
{
name => "75-100 Views",
id => '45499242@N00',
lbound => 75,
ubound => 99
},
{
name => "Centurian Club",
id => '38475367@N00',
lbound => 100,
ubound => 200
}
);
# Get a list of photos in the photostream.
sub getphotos {
my $userid = shift;
my $pagenum = shift;
my $pagelen = shift;
my $api = new Flickr::API({'key' => $api_key});
my $response = $api->execute_method("flickr.people.getPublicPhotos",
{
user_id => $userid,
per_page => $pagelen,
page => $pagenum
});
die "Error: $response->{error_message}\n" unless $response->{success};
my $xmlp = new XML::Simple;
my $xm = $xmlp->XMLin($response->{_content}, forcearray=>['photo']);
my $photos = $xm->{photos};
print "Page $photos->{page} of $photos->{pages}...\n";
my $photolist = $photos->{photo};
my $nphotos = scalar keys %{$photolist};
my $n = 0;
my @photoarr;
for my $id (keys %{$photolist}) {
my $photo = $photolist->{$id};
$photo->{id} = $id;
$photo->{url} = "http://www.flickr.com/photos/$photo->{owner}/$photo->{id}";
push @photoarr, $photo;
}
( $photos->{pages}, \@photoarr );
}
# Get view counts of the photos.
sub getviews {
my $photolist = shift;
my $agent = new LWP::UserAgent;
$agent->parse_head(0);
my $i = 0;
for my $photo (@$photolist) {
++$i;
print "Getting photo $i of @{[scalar(@$photolist)]}...\n";
my $retry_count = 0;
my $response;
do {
$response = $agent->get($photo->{url});
usleep 250000;
} while $retry_count++ < 3 and $response->is_error;
if ($response->is_error) {
warn $response->status_line, "\n";
next;
}
my $resp = $response->content;
if ($resp =~ /<li class="Stats">\s*Viewed <b>(\d+)<\/b> times\s*<\/li>/) {
$photo->{views} = $1;
}
}
}
# Check each photo's views group membership. Report the photos that have
# not been placed into their correct views groups.
sub checkgroups {
my $logfh = shift;
my $photolist = shift;
my $api = new Flickr::API({'key' => $api_key});
my $n = 0;
for my $group (@groups) {
print $logfh "<h2>Move these to $group->{name}</h2>\n";
print "Checking group $group->{name}\n";
my $i = 0;
for my $photo (@$photolist) {
defined $photo->{views} or next;
if ($photo->{views} >= $group->{lbound} and
$photo->{views} <= $group->{ubound}) {
++$n;
print "Checking photo $n of @{[scalar(@$photolist)]}...\n";
my $retry_count = 0;
my $response;
do {
$response = $api->execute_method("flickr.photos.getAllContexts",
{ photo_id => $photo->{id} });
usleep 250000;
} while $retry_count++ < 3 and not $response->{success};
unless ($response->{success}) {
warn "Error getting contexts for photo $photo->{id}: $response->{error_message}\n";
next;
}
my $xmlp = new XML::Simple;
my $xm = $xmlp->XMLin($response->{_content}, forcearray=>['pool']);
my $pool = $xm->{pool};
unless (defined $pool->{$group->{id}}) {
my $title = encode("iso-8859-1", $photo->{title});
++$i;
print $logfh <<EOM;
$i. <a href="$photo->{url}">$photo->{id}</a>: $title, <b>$photo->{views}</b> views<br>
EOM
}
}
}
}
}
# Open log file.
sub openlog {
my $logfn = sprintf("r%X.htm", time);
my $fh = new FileHandle $logfn, "w";
defined $fh or die "Error opening $logfn for writing: $!\n";
$fh->autoflush(1);
$fh;
}
# Process one page in the photostream.
sub processpage {
my $pagenum = shift;
my $pagelen = shift;
my ($totalpages, $photolist) = getphotos($myid, $pagenum, $pagelen);
getviews($photolist);
my $logfh = openlog();
print $logfh <<EOM;
<html>
<head>
<title>Page $pagenum of $totalpages</title>
</head>
<body>
<h1>Page $pagenum of $totalpages</h1>
EOM
checkgroups($logfh, $photolist);
print $logfh <<EOM;
</body>
</html>
EOM
$logfh->close;
}
sub usage {
print <<EOM;
self.pl [-pagelen=n] pagenum
-pagelen=n:
Set the page length to n.
n must be at least 1.
Default n is 100.
pagenum:
Page # to scan.
First page is 1.
Default is the first page.
EOM
exit 1;
}
my $pagelen = 100;
Getopt::Long::Configure("bundling_override");
GetOptions('pagelen=s' => \$pagelen) or usage();
die "Page length must be at least 1\n" if $pagelen < 1;
my $pagenum = shift;
defined $pagenum or $pagenum = 1;
processpage($pagenum, $pagelen);
__END__