Sunday, July 13, 2008

Flickr Photostream Ordered by Date Taken

After thinking about getting an iPhone since the day they came out I went out and bought a Nokia N95. It was a hard call, I think the main reason was how Apple locks down the iPhone so you can only do cool stuff with it if you bother to jailbreak it. It's just not worth it. Not to mention the sweet 5MP camera on the N95.

Well anyway, I found Showzu. Which lets me instantly post photos I take with the camera onto Flickr and Facebook. This really does solve a major problem with all digital cameras - upload. It's such a pain to copy the files off the camera, index and sort them, color correct them and then post them to someplace where they can be viewed easily. Part of this is the fact that the photos off the camera have such useless names (like dscf08329.jpg.) This means you have to open the photo you want to post, find the filename and then use the browser's find file dialog to upload each file (or at least of zip file you put together.) Not at all elegant. So Showzu is the perfect solution. Or at least it would seem.

Unfortunately the edition options in the phone are not the best. This would not be a problem, since Flickr has a rather nice built in editor. However, the edited photo becomes a new photo in the photo stream. How gay is that? So if I go back to color correct a few photos from a week ago, they will appear like I posted them today. Not cool.

Enter the Flickr::API to the rescue (it would seem.)

















































































































































































































































































































































































































































































#!/usr/bin/perl
##############################################################################################
## flick_dates.pl: Flickr API script to change the date taken to the date posted. ##
## Author : Jonathan Jeffus (jjeffus at gmail dot com) ##
## Copyright (C) 2007 Psylus Development, LLC. ##
##############################################################################################
## This software is released under the same terms as Perl itself (Artistic License) ##
##############################################################################################
use Carp;
use Flickr::API;
use Time::Local qw/timelocal/;
# On linux, comment this out and see open_in_browser()
use Win32::API;
##
## User Servicable Variables
##
my $api_key = '';
my $secret = '';
my $photos_to_update = 500;
##
## Get Write Permission
##
my ($api, $res);
# Connect to the Flickr api and get a frob for authentication.
$api = new Flickr::API({
'key' => $api_key,
'secret' => $secret
});
$res = $api->execute_method('flickr.auth.getFrob');
if (not defined $res) {
croak "Error: Did not get response object.\n";
} elsif ($res->{'success'} != 1) {
croak "Error $$res{'error_code'}: $$res{'error_message'}\n";
}
my $frob = $res->{'tree'}->{'children'}->[1]->{'children'}->[0]->{'content'};
my $url = $api->request_auth_url('write', $frob);
# Open the url in a web browser.
&open_in_browser($url);
# Wait for the user to click "Authorize" in the browser window.
print "A window will open requesting authorization. Hit enter after you grant the application access...\n";
my $line = <>;
# Now get a token.
$res = $api->execute_method('flickr.auth.getToken',
{'frob' => $frob,
'perms' => 'write'});
if (not defined $res) {
croak "Error: Did not get response object.\n";
} elsif ($res->{'success'} != 1) {
croak "Error $$res{'error_code'}: $$res{'error_message'}\n";
}
my $token = $res->{'tree'}->{'children'}->[1]->{'children'}->[1]->{'children'}->[0]->{'content'};
# This could be saved after the first time the application is authorized. This would prevent us from needing to do the first two steps.
print "Token: $token\n";
# Now search for the last $photos_to_update photos by the user.
$res = $api->execute_method('flickr.photos.search',
{'auth_token' => $token,
'user_id' => 'me',
'per_page' => $photos_to_update});
if (not defined $res) {
croak "Error: Did not get response object.\n";
} elsif ($res->{'success'} != 1) {
croak "Error $$res{'error_code'}: $$res{'error_message'}\n";
}
# Go through the response and get all the photo ids.
my $photos = $res->{'tree'}->{'children'}->[1]->{'children'};
my @photos;
foreach my $item (@$photos) {
if ($item->{'name'} eq 'photo') {
push @photos, $item->{'attributes'}->{'id'};
}
}
# Now go through all the photo ids and update them.
foreach my $photo (@photos) {
print "photo id : $photo\n";
# First getInfo on the photo.
$res = $api->execute_method('flickr.photos.getInfo',
{'auth_token' => $token,
'photo_id' => $photo});
if (not defined $res) {
croak "Error: Did not get response object.\n";
} elsif ($res->{'success'} != 1) {
croak "Error $$res{'error_code'}: $$res{'error_message'}\n";
}
my $info = $res->{'tree'}->{'children'}->[1]->{'children'};
# Get date_posted and date_taken.
my $dates;
foreach my $item (@$info) {
if ($item->{'name'} eq 'dates') {
$dates = $item->{'attributes'};
}
}
if (not defined $dates) {
croak "Error: No dates found in object.\n";
}
print "posted unix: ", $dates->{'posted'}, "\n";
print "posted 8601: ", &unixtime_to_iso8601($dates->{'posted'}), "\n";
print "taken old: ", $dates->{'taken'}, "\n";
# Parse the taken date (currently in iso8601 MySQL format.)
my ($taken);
if ($dates->{'taken'} =~ m/(\d\d\d\d)-(\d\d)-(\d\d).(\d\d):(\d\d):(\d\d)/) {
# And convert it back to seconds since the epoch.
$taken = timelocal($6, $5, $4, $3, int($2)-1, int($1)-1900);
print "taken unix: ", $taken, "\n";
print "taken 8601: ", &unixtime_to_iso8601($taken), "\n";
} else {
croak "Error: Invalid date: $$dates{'taken'}: Expected ISO 8601.\n";
}
# Now set the date_posted to the date_taken.
$res = $api->execute_method( 'flickr.photos.setDates',
{'auth_token' => $token,
'photo_id' => $photo,
'date_posted' => $taken});
if (not defined $res) {
croak "Error: Did not get response object.\n";
} elsif ($res->{'success'} != 1) {
croak "Error $$res{'error_code'}: $$res{'error_message'}\n";
}
print "\n";
}
sub open_in_browser {
my $url = shift();
my ($shell);
# On Windows
$shell=new Win32::API('shell32','ShellExecuteA',[qw(N P P P P I)],'N');
$shell->Call(0,'open', $url, 0, 0, 1 );
# On Linux (untested)
# system("`which firefox` '$url'");
}
sub unixtime_to_iso8601 {
my $time = shift();
my ($s, $i, $h, $d, $m, $y) = localtime($time);
$m += 1;
$y += 1900;
my $date = sprintf("%04d-%02d-%02d %02d:%02d:%02d", $y, $m, $d, $h, $i, $s);
return $date;
}

No comments: