NunoNunes.org

Loading
Entries by year
Entries by month
December
Sun Mon Tue Wed Thu Fri Sat
       
Powered by Blosxom
Creative Commons License

And we have photos… Almost.

Following yesterday’s post and in the interest of getting something out as soon as possible, I’ve made some headway into the Flickr::Photo class today.

Of course this was after some cleanups and slight changes to the Flickr::Person class.

I can now instantiate a photo object, see (part of) it’s info and get an object representing it’s owner, all auto-magically. Rocks!

In the mean time, it is a good thing I decided to leave the write part of the read/write equation for later as I noticed today (two days late!) that there was an email on the Flickr developers list informing that the ‘setters’ (the write methods) where changed and that they now all have to be done via POST instead of GET.

While this makes perfect sense, I’m pretty sure it will warrant some changes in the Flickr::API and until Cal makes those changes I’ll keep the write part on the back-burner. (As if it weren’t already there…) ;-)

The hardest part of making something like Flickr-Tools is that you just know that the second you put it up on CPAN there will be a ton of changes to the object’s API which will become immediately clear.

Oh well, release often, release early, warn your users, listen to the community feed-back and all that jazz.

I really wish I could make the first release during the coming weekend… I’m not sure I’ll be able to do it though, as real life is getting in the way. But I’ll surely try.

(Did I just say “real life”? Hum… It seems my moo/mud-user personality is trying to take over when I’m not looking!)

About this entry

Originally written on May 25, 2005 @ 21:26
Read article on it's own page (permalink)

How does it feel?

This is what was blasting in my car today on the way to work:

How does it feel
To treat me like you do
When you’ve laid your hands upon me
And told me who you are

I thought I was mistaken
I thought I heard your words
Tell me how do I feel
Tell me now how do I feel

Man, I’m old… fashioned.

About this entry

Originally written on May 25, 2005 @ 11:04
Read article on it's own page (permalink)

We have people!

I just couldn’t resist and after having finished the first version of the Flickr::API::* classes I just had to try and implement one of the high-level modules to test it out.

So I now have Flickr::Person full implemented (no tests just yet, though, I went way about this one the impatient way).

It took about 30 minutes to do it and works like a charm! It was extremely easy to write, it is lazy in getting data and, once it actually has to get any data, it caches it for future reference.

It’s great when things ‘just work’ like this. Quite a rush!

Well, but now I’ve got to be a good boy and go to bed, tomorrow I have a chiropractor’s appointment really early and I will pay for staying up late working on this.

Can’t wait to get the other three modules finished. This version of the modules is read-only (you can only get information from Flickr, and not all available information at that) but once I get it out the door and into CPAN I’ll start implementing the write part of it. And filling in the gaps on the read methods, of course.

Technorati Tags: ,

About this entry

Originally written on May 25, 2005 @ 01:09
Read article on it's own page (permalink)

Mock objects

Mock objects essentially rule.

With them I can trick my modules into asking my mock object for the data they would receive from a call to a third object (of which I know nothing about, except for the output it returns for a given input) and they are none the wiser about it. This is incredibly easy to do, and I’m not even sure I’m using it in the best and most efficient possible way!

So I’ve basically put aside the problems of testing with live data, with all that entails about having to have a live connection to the Internet, hopping that the Flickr API is responding, having to setup test data and so on.

Some people did make the point that this way, should the Flickr API change in the future, my module will still pass all the tests and then bomb out on the poor unsuspecting users. Which, of course, is absolutely true, but it is not what module testing is about. Module testing is about making sure that the code runs as expected on the platform it is being installed on. The API may change in the future, but this is something I have to find out by myself and make the necessary changes to the modules and release them again.

So now I’ve got a bunch of modules which take the results from the Flickr::API calls and turn them into a saner structure for a few selected calls (no time to do them all so far, but I’ve got the infrastructure set up so now it is just a question of filling up the gaps). All the calls I wanted to include in the first release of the distribution are done. Now to get the higher-level modules working with these and abstracting the User, Photo and Photoset concepts and off they go to CPAN.

This is actually fun!

Technorati Tags: ,

About this entry

Originally written on May 24, 2005 @ 19:41
Read article on it's own page (permalink)

Something new everyday

The responses to my post yesterday about testing with Flickr, both at use Perl; and here at nowhereland were great.

I made the post rather in a hurry and right after I’ve come across the issue so I really hadn’t given it much thought.

Had I thought about it, I would surely have gotten to the solution that some people pointed to, which is that I should just setup an account for testing or even ask the Flickr crew to set one up for the community to use. And that would have been acceptable, even if I weren’t totally happy with it. It would always feel like a kludgy solution which could require tweaking if ever someone made changes to the user data or it’s photos (which people would be able to do given the info on the module’s testing scripts). It would also mean that you’d have to have connectivity when you where installing the module (or force-install it which I’m always loath to do).

In the end it is a good thing that I did make the post in such a rush manner because another solution came up which has a lot of promise.

Two people pointed me to the concept of “mock objects” which, as Melo puts it, “represents an ideal Flickr, which always gives me the response I need”. This seems just perfect for this situation.

So now I have a new goal: learn how to use _ Test::MockObject_ and integrate it into the Flickr-Tools development process.

Who would have though it? It actually pays off to be lazy! Oh wait, all geeks know that… Right…

About this entry

Originally written on May 20, 2005 @ 12:06
Read article on it's own page (permalink)

On testing modules

I’ve been getting some good progress on the Flickr-Tools distro, mainly on the lower-level modules (Flickr::API::Photos, Flickr::API::People, etc). At this point I can already rewrite the pet project which got me into writing this group of Perl classes in the first place, using only these classes. Admitedly this is not much to boast about, but it feels nice anyway… :-).

On the way I’ve met some dead-ends and had to track back a few times, but nothing too alarming.

Only now I’ve come across a real stumper.

While developing the modules I’ve taken the “build your tests before writing any code” approach which is all fine and dandy while I’m working on it, but I just don’t know how I’m going to release the modules with the tests as they are now.

The problem is that testing anything useful at all requires not only the usage of a Flickr API key but also some rather precise information on a person’s info, a few test pictures, photosets, and so on.

Of course I’m using my own information for the tests, but I’m not really happy with releasing a module into the wild with all that information on it!

I know I could just capture the result of the original Flickr API response for each instance I needed it, change some values around and test my modules against that result but that is just evading the problem and a whole lot of extra work.

I just don’t know how I’m going to tackle this one…

About this entry

Originally written on May 19, 2005 @ 20:24
Read article on it's own page (permalink)

Depressing times

Indeed, depressing times…

Yesterday I filled out and filed in my tax return. It always breaks my heart. It is bad enough each month when I see my salary receipt, but when I actually do the math at the end of the year it just depresses the hell out of me. Not only the taxes themselves, but also the money that goes into social security, which sucks badly for people who are using it today and will not even be there for me when I retire anyway… Well, I’ll not delve into that anymore, I really have no wish to discuss it further, only to forget.

Right now I’m in the middle of installing all the Perl paraphernalia required to develop stuff in the iMac. I had forgotten what a pain it is to setup a Perl installation to develop XML related stuff. But things are going along at a good pace, nonetheless and soon I shall have Flickr::API and Flickr::Upload installed. I still had to force install SOAP::Lite and I do hate to do that, but I just can’t be bothered to track the problem down, I’ve already done enough of that during this session and I have a splitting head-ache which is urging me to go to bed ASAP, so that’s just how it’s going to stay.

The upturn of things is that I already have tickets for the Startwars premiere at a mega-screen cinema room. I’ve never actually been on that particular room and some people said that the screen on it is just too big for comfort, but I’m betting on the fact that there is no screen too big for Starwars so let’s see how that turns out.

About this entry

Originally written on May 17, 2005 @ 23:30
Read article on it's own page (permalink)

More thoughts on Flickr API

After some more thought (nothing like a bad day to get your brain working in the background…) I came to this conclusions about the classes and namespaces that make sense for the Perl Flickr API.

First I think there really is room for the two sets of modules/classes I discussed: a lower level one which simply models the published Flickr API directly on Perl structures of hashes and arrays, and a higher level one which models the “logical” level of users, photos, photosets, etc.

Then I seem to have reached a reasonable naming structure for them. My current plan goes along these lines:

The lower-level API-mapping classes

These should go into the Flickr::API namespace and should be named following the Flickr API’s naming convention, namely there should be the following classes:

  • Flickr::API::People
  • Flickr::API::Photos
  • Flickr::API::Photosets
  • Flickr::API::

Each of these classes should then implement the functions that are published on the API, for instance Flickr::API::Photos::getInfo(), Flickr::API::Photos::search() and so on.

The higher-level concepts-mapping classes

Then there are the classes which map concepts such as a user or a photo. As I described in the previous post, these objects should rely on the previous ones to manage the communication with Flickr for them and should implement a representation of all the information that Flickr has on each item.

The way I see it now, the namespace for these objects should be the base Flickr namespace itself and there should exist the following classes:

  • Flickr::Person
  • Flickr::Photo
  • Flickr::Photoset
  • Flickr::

I’ve already started writing some code, mainly the tests (aren’t I a good little programmer?) and even though I will be away for the weekend on a small family gathering I’ll try and have something done by monday when I’ll have Internet access again and can try out my code on live data.

Technorati Tags: ,

About this entry

Originally written on May 13, 2005 @ 21:07
Read article on it's own page (permalink)

First post

Well, it is done: my previous entry made me create my first post on my use Perl; Journal. Cool! :-)

About this entry

Originally written on May 13, 2005 @ 12:41
Read article on it's own page (permalink)

An easier Flickr API in Perl

Sooo… Last night Tuxa went to a farewell dinner she and her friends threw for a colleague and I was left home alone without the usual many urgent things to do, so I took a stab at the Flickr modules I’m starting to write.

And now I’m trying to decide which is the better approach to take.

One possible approach would be to create a Flickr object which has a method for each of the Flickr API calls, such as $flickr->photosgetInfo_ or $flickr->peoplefindByEmail_ and so on.
The object should then return a hash structure that closely resembles the documented result for that call, so for example the $flickr->photosgetInfo_ method (described here) should return something along the lines of the following:

{
  id => "2733",
  secret => "123456",
  server => "12",
  isfavorite => "0",
  license => "3",
  rotation => "90",
  owner => {
             nsid => "12037949754@N01",
             username => "Bees",
             realname => "Cal Henderson",
             location => "Bedford, UK",
           },
  title => "orford_castle_taster",
  description => "hello!",
  visibility => {
                  ispublic => "1",
                  isfriend => "0",
                  isfamily => "0",
                },
  dates => {
             posted => "1100897479",
             taken => "2004-11-19 12:51:19",
             takengranularity="0",
           },
  permissions => {
                   permcomment="3",
                   permaddmeta="2",
                 },
  editability => {
                   cancomment="1",
                   canaddmeta="1",
                 },
  comments => 1,
  notes => [
             {
               id => "313",
               author => "12037949754@N01",
               authorname => "Bees",
               x => "10",
               y="10",
               w="50",
               h="50",
               content => "foo",
             },
           ],
  tags => [
            {
              id => "1234",
              author => "12037949754@N01"
              raw => "woo yay",
              content => "wooyay",
            },
            {
              id => "1235",
              author => "12037949754@N01",
              raw="hoopla",
              content => "hoopla",
            },
          ],
}

This kind of approach appeals to me because it gives me access to just the plain data, in a easy way, without all the XML-parser-generated-cruft, in a much more “perlish” way.

But while I consider this an improvement over the current Flickr::API module (which is great, by the way, and will be used as the foundation for all of this), it may still be too low-level for many people to use.

So there is another possible approach (OK, there are many other possible approaches but I’m focusing one on in particular) ;-) which is to create a set of higher-level objects which represent an entity like a “person” or a “photo” or a “photoset”.

Then the user would simply ask the object to instantiate, say, the Flickr user whose email is something@somesuch (using flickr.people.findByEmail on the background) or the photo whose id is someid (using flickr.photos.getInfo). Then, if the user wanted some more information on the photo, for example, she could ask for the lens aperture used ($photo->apperture()) and the object would fetch the EXIF information for the photo in question (using flickr.photos.getExif), load it into the $photo object and return the information.
A major point to make here is that the object would fetch information in a “lazy” manner, so as to limit the number of interactions it has to have with the Flickr server.

My immediate needs are more than adequately met by the first approach to the modules and, therefore, I guess I’ll surely implement them right now, but the second approach could be very interesting indeed…
But then, now that I think about it in a more structured way, the second way depends on the first one to process all the results from the raw API and convert them into useful data, so I may well end up implementing it too in the future…

What I haven’t figured out just yet is which name-space to use.
Should I go for Flickr::API::Methods (as in Flickr::API::Methods::peoplefindByEmail()_ or Flickr::API::Methods::photosgetInfo())?
Or maybe go for _Flickr::Tools

Or I could go with Flickr::Photos (Flickr::Photos::getInfo() for instance), Flickr::People (Flickr::People::findByUsername()). Actually I think I like this last version best…

As for the higher-level modules I’m not entirely convinced they should even be in the Flickr namespace at all… But then I don’t have to decide on it just yet so let’s see what my mind is aimed at when I get to it.

If anyone reading this has any kind of comment, remark, idea, suggestion or tough about the subject I really would appreciate feedback. (Hey, I guess this is the first time I explicitly ask for feed-back here… Let’s see how it goes. I should probably start using the use Perl; journal —which I’ve never used at all— for this though… maybe I’ll cross-post there.)

Technorati Tags: ,

About this entry

Originally written on May 13, 2005 @ 12:19
Read article on it's own page (permalink)

So while keeping with my

So while keeping with my latest “keep fit craze” (actually that’s not very correct, it’s more like a “get fit craze” but let’s roll with it), today I went back to my old love —swimming.

Since I’ve been essentially a couch potato for quite a long time now, I decided to get back into it very gently. So I decided to try out the gym’s pool which is only 25m, instead of going for the pool I used to swim at, which is an olympic, 50m pool.

Also I decided to not do a real workout today, but just swim around in the three easy styles and see how I felt and what kind of shape I am in.

And the verdict was really fast to come by, so here it is, together with some notes and comments:

  • The shape I’m in is bad, of course, but not as bad as I expected. It took me almost half an hour to do a measly 1.000m, but I didn’t die doing it, so that’s not so bad;
  • I absolutely need a scheme to follow. If I just go to the pool and see what happens I will muck around and not do anything useful at all. I’ve felt this before, so this is only confirmation of what I already knew. It’s a good thing I kept a record of my workouts from when I was trying (already without great success) to take swimming seriously. I guess I’ll just have to print out some sessions and stick to that for the time being;
  • The 25m pool really breaks your rhythm when you don’t do your turns right. Of course for now it is more than adequate for me, but I need to build my resistance up to the level where I can swim non-stop (including decent turns at the ends of the pool) for a whole 500m or 600m, which where once my warm-up routine. When (if) I get back to that point I may get back to the big pool at Estádio Nacional in Jamor;

About this entry

Originally written on May 13, 2005 @ 10:53
Read article on it's own page (permalink)

AJAX

AJAX is (yet another) acronym which is short for “Asynchronous JavaScript + XML”.

But what AJAX is about is using a group of technologies which are already out there and which are well understood, and combining them in order to provide better, more responsive and more powerful web applications.

In a nutshell AJAX makes use of the following technologies:

  • XHTML and CSS for presentation and design;
  • The DOM for interaction with and dynamic display of data;
  • XML (and, of course, XSLT for data manipulation and transmission;
  • XMLHttpRequest for asynchronous data fetching;
  • JavaScript to bind it all together and control everything.

Resources

About this entry

Originally written on May 11, 2005 @ 12:06
Read article on it's own page (permalink)

The circus without a clown

Just came back from the circus. But not just any circus, no, this time I went to see a Chinese circus.

For the first time in a long, long time I’ve felt like a child. I caught myself gazing at what was happening in the ring, jaw ajar and eyes wide open so many times during the show I just couldn’t believe it.

For three years I’ve been trying to go and see this circus and there was always some thing or other that got in the way, but this year Tuxa and I decided to just go and the only thing I can say about it is that I feel really stupid about not having gone before.

I really enjoy the circus and every year I at least go to the Christmas circus, but from now on it will be very difficult to ever again face the “eastern” circus the way I’ve always done. The fact is that apart from the “Cirque Du Soleil” nothing comes close to this. Not even remotely! (And the “Cirque Du Soleil” is a different kind of show anyway so the only possible comparison is in the spectacularity of each show).

And the best part of the chinese circus is that there are no clowns and no animals! Hurray for that!!

I won’t go into much detail because today was a rather long day and I’m really tired, but I just want to relate the following story: we ran into an old friend of Tuxa’s at the circus and after the show we talked for a few minutes before the cold drove us away. One of his remarks about the show went something along these lines —“Well, now we know what the Chinese do with at least some of the many superb athletes they have, which don’t make it into their olympic teams”.

Yes, it really is that good.

About this entry

Originally written on May 08, 2005 @ 00:20
Read article on it's own page (permalink)

Flickerize My Photolog

What is This then?

This page contains a script for getting all the photos from a given flickr photoset and some HTMl and CSS to display them in a nice way.

Introduction and Motivation

This script was born out of my desire to use Flickr as a “storage engine” for my photolog.

I wanted to take a specific photoset from my Flickr account and display those photos as a photolog, on my site, with my own design.

The best way to do it (OK, it may or may not be the best, but it sure is the most fun) was via it’s API, specifically, the Flickr::API Perl’s API.

At the time of this writing the script goes out and fetches the information on the photos but doesn’t do anything intelligent with it. It is a work in progress and it is getting late…

Source Code

This version of the source code still has it’s own functions to parse the response from the Flickr::API::Response object. This job will be moved to a new set of modules and will be removed from here but until then here it is.

One more note: this script outputs something which is very specific to my own test site and it expects to have a combination of pages which include the files it outputs and also a CSS style-sheet to make it all look good.

In this page you will also find the companion files for my test setup.

#!/usr/bin/perl -w

use strict;
use Flickr::API;
use Data::Dumper;

my $DEBUG=1;
my $flickr_api_key='<YOUR API KEY>';
my $flickr_username='<YOUR FLICKR USERNAME>';
my $desired_photoset='<YOUR PHOTOSET NAME>';
my $api = new Flickr::API({'key' => $flickr_api_key});
my $local_photos_path='<LOCAL PATH FOR THE SITE>';
my $local_index_file=$local_photos_path.'/photolistbody.html';
my $local_individual_photos_path=$local_photos_path.'/photos';


# Get the nsid from the username
my $findUser = $api->execute_method('flickr.people.findByUsername',
           {
         'username' => $flickr_username
           });
testError($findUser);

my $goodies = $findUser->{tree}{children}[1]{attributes};
my $nsid = $goodies->{nsid};
print STDERR "Got nsid: $nsid\n" if $DEBUG;

# Now get the required photoset's ID
my $getList = $api->execute_method('flickr.photosets.getList', {
           'user_id' => $nsid
           });
testError($getList);

my $photoset_id;
foreach $goodies (@{$getList->{tree}{children}[1]{children}}) {
  next unless (defined($goodies->{name})
           and ($goodies->{name} eq 'photoset'));
  my $found_photoset=0;
  foreach my $this_photoset (@{$goodies->{children}}) {
    next unless (defined($this_photoset->{name})
             and ($this_photoset->{name} eq 'title'));
    if ($this_photoset->{children}[0]{content} eq $desired_photoset)
    {
    $found_photoset = 1;
    last;
    }
  }
  if ($found_photoset) {
    $photoset_id = $goodies->{attributes}{id};
    last;
  }
}
print STDERR "Got the ID for the '$desired_photoset' photoset: $photoset_id\n"
  if $DEBUG;

# Let's finally get the pictures from the photoset
my $getPhotos = $api->execute_method('flickr.photosets.getPhotos', {
           'photoset_id' => $photoset_id
           });
testError($getPhotos);

my @photos;
foreach $goodies (@{$getPhotos->{tree}{children}[1]{children}}) {
  next unless (defined($goodies->{name}) and ($goodies->{name} eq 'photo'));
  unshift @photos, {title => $goodies->{attributes}{title},
         flickrurl => photoFlickrURL($goodies->{attributes}),
         localurl => photoLocalURL($goodies->{attributes}),
         flickrthumb => photoFlickrURL($goodies->{attributes},'s'),
         id => $goodies->{attributes}{id},
         secret => $goodies->{attributes}{secret}};
}

foreach my $photo (@photos) {
  my $getInfo = $api->execute_method('flickr.photos.getInfo', {
        photo_id => $photo->{id},
        secret => $photo->{secret},
        });
  testError($getInfo);

  # Get all the relevant data for each photo
  my $info_data = readInfo($getInfo);
  foreach my $data_item (keys(%$info_data)) {
    $photo->{$data_item} = $info_data->{$data_item};
  } 

  my $getExif = $api->execute_method('flickr.photos.getExif', {
        photo_id => $photo->{id},
        secret => $photo->{secret},
        });
  testError($getExif);

  # Get all the EXIF data for each photo
  $photo->{exif} = readExif ($getExif);
}

# Finaly write the index file and the individual photo files
open INDEX, ">$local_index_file" or die "Could not open index file for writing: $!";
print INDEX "<ul id=\"thumbList\">\n";
my $index=0;
foreach my $photo (@photos) {
  open PHOTOFILE, ">$local_individual_photos_path/".$photo->{id}.".html" or die "Could not open photo file for writing: $!";
  print INDEX "<li><a href=\"".$photo->{localurl}."\"><span class=\"thumbNail\"><img src=\"".$photo->{flickrthumb}."\" alt=\"".$photo->{title}."\" /></span><span class=\"thumbNailTitle\">".$photo->{title}."</span></a></li>\n";
  print PHOTOFILE "<ul class=\"photoNav\">\n";
  if (exists $photos[$index+1]) {
    print PHOTOFILE "<li><a href=\"".$photos[$index+1]->{localurl}."\"><--</a></li>\n";
  } else {
    print PHOTOFILE "<li>|--</li>\n";
  }
  print PHOTOFILE "<li><a href=\"ispy.html\">index</a></li>\n";
  if ($index) {
    print PHOTOFILE "<li><a href=\"".$photos[$index-1]->{localurl}."\">--></a></li>\n";
  } else {
    print PHOTOFILE "<li>--|</a></li>\n";
  }
  print PHOTOFILE "</ul>\n";
  print PHOTOFILE "<h1 id=\"photoTitle\">".$photo->{title}."</h1>\n";
  print PHOTOFILE "<div id=\"photoBig\"><img src=\"".$photo->{flickrurl}."\" alt=\"".$photo->{title}."\" /></div>\n";
  print PHOTOFILE "<p id=\"photoDescription\">".$photo->{description}."</p>\n"
    if defined $photo->{description};
  print PHOTOFILE "<div id=\"photoData\">\n";
  print PHOTOFILE "<p id=\"photoDate\">Photographed on: ".$photo->{date_taken}."</p>\n"
    if defined $photo->{date_taken};
  if (exists $photo->{exif}) {
    print PHOTOFILE "<ul id=\"EXIFData\">\n";
    foreach my $exifItemName (keys(%{$photo->{exif}})) {
      if ($exifItemName eq 'cameramodel') {
    print PHOTOFILE "<li>Camera model: ".$photo->{exif}{$exifItemName}."</li>\n";
      } elsif ($exifItemName eq 'shutterspeed') {
    print PHOTOFILE "<li>Shutter speed: 1/".eval($photo->{exif}{$exifItemName})."s</li>\n";
      } elsif ($exifItemName eq 'aperture') {
    print PHOTOFILE "<li>Lens aperture: f/".eval($photo->{exif}{$exifItemName})."</li>\n";
      } elsif ($exifItemName eq 'ISOspeed') {
    print PHOTOFILE "<li>ISO speed: ".$photo->{exif}{$exifItemName}."</li>\n";
      } elsif ($exifItemName eq 'focallength') {
    print PHOTOFILE "<li>Focal length: ".eval($photo->{exif}{$exifItemName})." mm (35mm equivalent: ".eval($photo->{exif}{$exifItemName})*1.6."mm)</li>\n";
      } elsif ($exifItemName eq 'exposurebias') {
    print PHOTOFILE "<li>Exposure bias: ".eval($photo->{exif}{$exifItemName})."EV</li>\n";
      }
    }
    print PHOTOFILE "</ul>\n";
  }
  print PHOTOFILE "</div>\n";
  close PHOTOFILE;
  $index++;
}
print INDEX "</ul>\n";
close INDEX;



# print STDERR Dumper(\@photos) if $DEBUG;

print STDERR "Got ".scalar(@photos)." photos\n" if $DEBUG;





sub testError {
  my $response = shift;

  die "Error getting data from flickr: got error ".
    $response->{error_code}.
    " (".
    $response->{error_message}
    .")" if (!$response->{success});
}





sub photoFlickrURL {
  my $attributes = shift;
  my $size = shift || 'o';

  # Check out http://www.flickr.com/services/api/misc.urls.html for
  # the URL translation algorithm. At this time it takes this form:
  # http://photos{server-id}.flickr.com/{id}_{secret}_[mstb].jpg
  # 
  die "Error getting photo attributes" unless $attributes;
  my $photo_id;
  if (defined($attributes->{id})) {
    $photo_id .= $attributes->{id};
  } else {
    die "Didn't get a photo ID at all!";
  }

  my $server_id;
  if (defined($attributes->{server})) {
    $server_id .= $attributes->{server};
  } else {
    die "Didn't get the server_id from the photo with ID $photo_id";
  } 

  my $secret;
  if (defined($attributes->{secret})) {
    $secret .= $attributes->{secret};
  } else {
    die "Didn't get the secret from the photo with ID $photo_id";
  } 

  my $url = "http://photos$server_id.flickr.com/$photo_id\_$secret\_$size.jpg";
  return $url;
}





sub photoLocalURL {
  my $attributes = shift;

  die "Error getting photo attributes" unless $attributes;

  my $photo_id;
  if (defined($attributes->{id})) {
    $photo_id .= $attributes->{id};
  } else {
    die "Didn't get a photo ID at all!";
  }

  my $photo_title;
  if (defined($attributes->{title})) {
    $photo_title .= $attributes->{title};
  }

  my $url = "photo.html?phototitle=$photo_title&photoid=$photo_id";
  return $url;
}





sub readInfo {
  my $infoData = shift;

  die "Didn't get the photo info!" unless $infoData;

  my $photo_info;
  foreach my $photo_data_item (@{$infoData->{tree}{children}[1]{children}}) {
    my $a = $photo_data_item->{name};
    if ((defined $a) and ($a)) {
      if ($a eq 'description') {
    $photo_info->{description} = $photo_data_item->{children}[0]{content};
      }
      if ($a eq 'visibility') {
    $photo_info->{public} = $photo_data_item->{attributes}{ispublic};
      }
      if ($a eq 'dates') {
    $photo_info->{date_taken} = $photo_data_item->{attributes}{taken};
    $photo_info->{date_posted} = $photo_data_item->{attributes}{posted};
      }

    }
  }

  return $photo_info;
}





sub readExif {
  my $exifData = shift;

  die "Didn't get the EXIF data!" unless $exifData;

  my $photo_exif;
  foreach my $photo_exif_item (@{$exifData->{tree}{children}[1]{children}}) {
    my $a = $photo_exif_item->{name};
    if ((defined $a) and ($a eq 'exif')) {
      my $label = $photo_exif_item->{attributes}{label};
      my $content = $photo_exif_item->{children}[1]{children}[0]{content};
      if ($label eq 'Model') {
    $photo_exif->{cameramodel} = $content;
      } elsif ($label eq 'ISO Speed') {
    $photo_exif->{ISOspeed} = $content;
      } elsif ($label eq 'Shutter Speed') {
    $photo_exif->{shutterspeed} = $content;
      } elsif ($label eq 'Aperture') {
    $photo_exif->{aperture} = $content;
      } elsif ($label eq 'Exposure Bias') {
    $photo_exif->{exposurebias} = $content;
      } elsif ($label eq 'Focal Length') {
    $photo_exif->{focallength} = $content;
      } 
    }
  }

  return $photo_exif;
}

The main index file

This file is called ispy.html and it is the main entrance page.
Mostly it just includes the main page generated by the script.

And a quick note: Yes, I do use PHP for this. It is just so right for this task… ;-)

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>iSpy</title>
<link rel="stylesheet" href="style.css" type="text/css" />
</head>
<body>
<? include "photolistbody.html" ?>
</body>
</html>

The individual photo page

This is the file which includes each individual photo (whose content is generated by the script).

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<?
  $phototitle = $_GET[phototitle];
  $photoid = $_GET[photoid];
?>

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>iSpy - <? print $phototitle ?></title>
<link rel="stylesheet" href="style.css" type="text/css" />
</head>
<body id="photoDisplay">
<? include "photos/$photoid.html" ?>
</body>
</html>

The Style-sheet

This is the style.css file. I’m no CSS wizard, so this is essentially a test of my own.

#thumbList {
  list-style-type: none;
  width: 100px;
  /*margin: 0 auto 0 auto;*/
}

#thumbList li {
  margin-top: 20px;
}

#thumbList li a {
  text-decoration: none;
}

#thumbList li a:hover {
  text-decoration: underline;
  color: #ab5518;
}

.thumbNail {
  display: block;
  text-align: center;
}

.thumbNail img {
  border: none;
}

.thumbNailTitle {
  font-family: verdana, arial; 
  font-size: 80%;
  display: block;
  text-align: center;
}

#photoDisplay {
  width: 800px;
  margin: 0 auto 0 auto;
  font-family: verdana, arial;
  color: #999999;
  background-color: #333333;
}

#photoDisplay h1 {
  text-align: center;
}

.photoNav {
  list-style-type: none;
  text-align: center;
  margin: 20px auto 0 auto;
  /*border: 1px solid red;*/
}

.photoNav li {
  display: inline;
  /*border: 1px solid yellow;*/
}

.photoNav li a {
  text-decoration: none;
  color: #999999;
}

.photoNav li a:hover {
  text-decoration: underline;
  color: #ab5518;
}

#photoBig {
  margin: 0 auto 0 auto;
  text-align: center;
}

#photoBig img {
  border: 35px solid #222222;
}

#photoDescription {
  width: 600px;
  margin: 20px auto 0 auto;
  padding: 15px;
  border: 2px solid #222222;
  background-color: #2f2f2f;
  font-family: verdana, arial;
  text-align: left;
  font-size: 100%;
}

#photoData {
  width: 600px;
  margin: 20px auto 50px auto;
  padding: 5px;
  border: 2px solid #222222;
  background-color: #2f2f2f;
  text-align: left;
  font-size: 75%;
  font-family: verdana, arial;
}

#EXIFData {
  list-style-type: none;
}

About this entry

Originally written on May 06, 2005 @ 02:08
Read article on it's own page (permalink)

A frase

Dizem que uma imagem vale por mil palavras, mas desta vez a coisa aconteceu ao contrário.

A frase do momento (e candidata a frase inspiracional do ano, no meu ranking pessoal) é a seguinte: “Não temos falta de recursos. Não temos; O que existe é falta de ideias”.

Deixando de lado o óbvio, esta frase faz-me vir à cabeça uma imagem muito clara que eu, por não conseguir desenhar nem que a minha vida dependa disso, não consigo reproduzir, mas cuja ideia é muito fácil de transmitir: Imaginem uma cena passada num restaurante ou snack-bar em que um homem claramente identificado como activista do movimento “Acabem com a violência, Salvem Os Ovos” está a encomendar para o seu almoço uma bela omelete dupla.

Rebuscado? Surreal? Pode ser que sim, mas por outro lado não temos de ser (mais) idiotas?

About this entry

Originally written on May 05, 2005 @ 10:50
Read article on it's own page (permalink)

The Feed Joiner

tags: coding,programming,scripting

While waiting for the rest of the lunch party, I decided to check out the feed joiner script and, to my surprise, things appear to be a-OK!

So much so that I’ve decide to integrate my wiki’s recently edited pages feed to it, just for the heck of it. And it works! It doesn’t have any useful information on this particular feed, but it worked like a charm first time.

Also, I’ve put up a small page about it, with the source code, on the wiki. It is here.

And now: to lunch!

About this entry

Originally written on May 03, 2005 @ 14:08
Read article on it's own page (permalink)

Feed Joiner

What is it?

Feed Joiner is a script that joins several RSS or ATOM feeds into a single ATOM feed.

Introduction and motivation

I’ve had the need to take all the feeds that I create from the various instances of my on-line presence and clump it together into a master feed for some time now.

Well, one day I just decided to get to work and just do it.

This is the result. So far it is very experimental and it is kind of ugly.

Whishlist and To-Dos

This is what I hope to improve in the near future:

  • Make it auto-detect whether a feed is ATOM or some kind of RSS and treat it accordingly;
  • Sort all the feed items on the master feed (the date on each individual item is good enough for a good reader to sort it, but it would be more elegant to pre-sort them in the feed itself);
  • Handle failings in some sort of sensible way (which I still have to figure out what it actually means: do I drop the items from a source feed that has a problem? Do I use the previous version of the source feed (I’d have to cache it somewhere for that)? Do I just fail to create the master feed?);
  • Make it easier to configure. Especially take out all those hammered in strings and options;
  • Make it all around more robust.

The source code

Anyway, here is the current source code for your perusal (and no, I never claimed it was pretty, but it sure gets the job done!):

#!/usr/bin/perl -w

use strict;

use LWP::Simple;
use XML::RAI;
use XML::Atom::Syndication;
use XML::Atom::SimpleFeed;

my %urls = (
  'http://nowhereland.nunonunes.org/atom.xml' => {
    type => 'atom',
    name => 'Nowhereland',
  },
  'http://www.flickr.com/services/feeds/photos_public.gne?id=92591068@N00&tags=nunonunesispy&format=atom_03' => {
    type => 'atom',
    name => 'iSpy',
  },
  'http://del.icio.us/rss/nunonunes' => {
    type => 'rss',
    name => 'Links',
  },
);

my @newsitems;

# Let's get all the data from all the sourcess
print STDERR "Starting the master feed refresh...\n";

foreach my $url (keys %urls) {

  my $content = get($url);
  my $type = $urls{$url}{type};
  my $feed_title = $urls{$url}{name};

  die "Error getting the feed from $feed_title: $!" unless $content;

  if ($type eq 'atom') {
    my $atomic = XML::Atom::Syndication->instance;

    my $doc = $atomic->parse($content);
    foreach ($doc->query('//entry')) {
    my $newsitem = undef;

    $newsitem->{title} = "[$feed_title]";
    $newsitem->{title} .= " ".$_->query('title')->text_value
      if $_->query('title');

    $newsitem->{content} =  $newsitem->{content}->text_value
      if $newsitem->{content};

    $newsitem->{link} = $_->query('link/@href')
      if $_->query('link/@href');

    $newsitem->{modified} = $_->query('modified')->text_value
      if $_->query('modified');

    $newsitem->{summary} = $_->query('summary')->text_value
      if $_->query('summary');

    $newsitem->{content} = $_->query('content')->text_value
      if $_->query('content');

    $newsitem->{issued} = $_->query('issued')->text_value
      if $_->query('issued');

    $newsitem->{id} = $_->query('id')->text_value
      if $_->query('id');

    $newsitem->{created} = $_->query('created')->text_value
      if $_->query('created');

    push @newsitems, $newsitem;
    }
  }
  elsif ($type eq 'rss') {
    my $rai = XML::RAI->parse($content);

    foreach my $item ( @{$rai->items} ) {
      my $newsitem = undef;

      $newsitem->{title} =  "[$feed_title] ".$item->title;

      $newsitem->{link} = $item->link if $item->link;

      $newsitem->{content} = $item->content if $item->content;

      $newsitem->{issued} = $item->issued if $item->issued;

      push @newsitems, $newsitem;
    }

  }

}

# Now let's build the aggregate feed...

my $atomfeed = XML::Atom::SimpleFeed->new(
  title => "Planet Nuno Nunes",
  link => "http://nunonunes.org/",
  tagline => "All things regarding Nuno Nunes - A collection of all the relevant feeds.",
  author => {
    name => "Nuno Nunes",
    url => "http://nunonunes.org/",
  }
)
or die "Error creating the aggregate feed: $!";

foreach (@newsitems) {
  $atomfeed->add_entry(
    %$_,
    author => {
      name => "Nuno Nunes",
      url => "http://nunonunes.org/",
    }
  )
  or die "Error adding item (\"".$_->{title}."\") to aggregate feed: $!";
}

$atomfeed->print;

print STDERR "Done refreshing the master feed.\n";

1;

About this entry

Originally written on May 03, 2005 @ 13:50
Read article on it's own page (permalink)

A bit of evening hacking

Having stayed home this evening (one of the few evenings when I actually have nothing planned outside), I decided to see if I could do something about a particular hitch I’ve been having for a while — getting all the relevant feeds I generate consolidated into one big feed.

I have the weblog (Nowhereland) and it’s feed, I have the links feed (powered by del.icio.us), I have the (sorry excuse at an attempt at a) photolog - ispy [Update: This site is no longer alive] (which is being changed in order to be powered by flickr) and a few more which I’m not sure I’ll want to get into the main feed right now.

These days I haven’t been really inspired to write in the weblog, but I have been active in both the photolog and the links gathering arena (not to mention the wiki, but this will have to wait until a second round), so it really bugs me that it appears as if I am just slacking off and fall bellow the radar when I’m actually getting stuff out there.

Also I now my readers want to know everything which is happening to me, not just each part individually. All three of them. Me included. And my mom. And my wife. Or maybe not…

So while I will almost certainly retain the individual feeds for each source, I will start to push the aggregate feed as the master feed for my site.

This will help with the outsourcing of parts of my site, as it allows me to change providers of services if and when I see fit without affecting (much) the way people get my content.

So anyway, I just did a quick round up of interesting Perl modules and clobbered a prototype script together to get the ball rolling. It most certainly will fail in spectacular and exciting ways before I can trust it enough to urge people to make the switch, but in the mean time it is already up at http://nunonunes.org/atom.xml. It is alpha code (I’ve written it, copied it to the development server and now I’m going to go to bed without even trying it out because otherwise this would last until very, very late) and it will be up and down as I toy with it and kick it into some sort of shape, but if you want to play with it too the source code is up in the wiki.

It is actually kind of fun to see how this sort of stuff still gets me in a zone (briefly, of course, as it didn’t take that long to write this). I was hacking away in front of the TV (something I rarely do) and I was watching Eurosport. The finals for the world snooker tournament where on and I love to watch those.
But then I got my head up and the tournament was over (didn’t even get to know who won!) and there was a football match on (that is soccer if you are of the American persuasion).
What’s so funny about that you ask? Well, I absolutely hate football. The only good thing I find about the game is that on match days the streets tend to be a bit more clear of traffic, and yet I was coding with a match going on on the TV and didn’t even notice it for a good few minutes.
Amazing! Now if it where a few years ago this kind of concentration could have gone on for hours but for now this is good enough anyway. :-)

Update: Turns out my old(ish) RedHat 9 installation didn’t have all the modules I needed to get it working. And installing all the modules required me to upgrade the version of libxml. At this hour I just wasn’t up to it, so the prototype lives instead at http://nowhereland.nunonunes.org/full-atom.xml. And let me tell you, installing Perl modules on a machine with this kind of CPU power is a serious turn-on!

About this entry

Originally written on May 03, 2005 @ 01:52
Read article on it's own page (permalink)

The content of this site is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 2.5 License.