randomfox (randomfox) wrote,
randomfox
randomfox

Flickr Views Group Suggestions for Photostream

#!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__

Subscribe
  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 0 comments