Picture of the Day

I’ve gotten some feedback on my Pic ‘O the Day feature that I’ve added to the left-hand column, most asking just how I did it.

The assumption is that it’s database driven; it’s not.

Since I am on Blogger, I’m pretty much stuck with a static site that’s written out by Blogger from the database they host and own.

This is bad and good:

  • Bad: I don’t have control over the templates, database and other functions like I do in most of my sites/my other development efforts. I have to funnel all my efforts through the Blogger tool.
  • Good: Since I am at Blogger’s mercy, I have to “roll my own” if I want additional functionality.

An example of such is the RSS (XML) feed that this blog has – it’s a Perl script that runs every five minutes from my home box: Grabs the index pages, parses out the necessary elements (strips HTML..) and writes out and uploads the RSS feed.

Why is this good??

Because I learn from doing this stuff. If Blogger had a built-in RSS feed option, I would definitely use it. They don’t currently have one, so I set one up myself from scratch.

Is it elegant? Nah.

Does it work. Yep.

That’s good.

OK – back to the subject at hand: Picture of the day.

Again, this is a Perl script that I run from home (my host doesn’t allow CRON access…another obstacle!).

Basically, it uses the Net::Telnet package. Using this package, I – though the Perl script – perform the following tasks:

  • “Telnet” to my server and log in
  • Get listing of all JPGs in the full-sized image directory
  • Select one of these images at random
  • Copy the thumbnail and full-sized image that is today’s random picture to “random.jpg” in each directory (full-sized and thumbnail).

That’s it – about 20 lines of code, reproduced below:


#! /usr/bin/perl

$myServer = "[server name]";
$myUsername = "[username]";
$myPassword = "[password]";
$imagesFull = "[path to full images]";

# create telnet object
my ($t);
use Net::Telnet ();
$t = new Net::Telnet;
$t->open($myServer);

## Wait for first prompt and "hit return".
$t->waitfor('/User\@domain:.*$/');
$t->print($myUsername);

## Wait for second prompt and respond with password.
$t->waitfor('/Password.*$/');
$t->print($myPassword);
$t->waitfor('/vde.*$/');

## Read the images in the full-sized image directory, one per line
$t->cmd("cd $imagesFull");
@remote = $t->cmd("ls -1 *.jpg");
pop(@remote); # remove last element; the shell cursor

# get random pic
srand;
$random = $remote[rand @remote];
chomp($random); # remove line feed from STDIN

## copy this file to the "random.jpg" file in the full and thumb dirs
$t->cmd("cp $random random.jpg"); #FULL pic
$t->cmd("cp ../thumb/$random ../thumb/random.jpg"); #THUMB pic

exit;

That’s the hard part: Then I just set a Cron job on my local machine and it fires at the interval I want. (I haven’t firmed this up, but I’ll probably stick to once a day.)

I had originally set this process up with the Net::FTP module (because I had done work with this module before), but this didn’t make a lot of sense – I could easily pull back the directory listing, but FTP doesn’t support remote system copy operations (delete only).

So I initially had a script – that worked fine with using Net::FTP – but that meant I had to find the random image (no biggie), but then I had to download the day’s pic and upload it again with the new name (random.jpg).

For both the full-sized pic and the thumbnail.

Doesn’t make a lot of sense to do four file transfers – and the full-sized images can/could be quite large – when two telnet commands (“copy [pic o day] random.jpg” for each – full and thumbnail – image) will do the same thing!

I knew there had to be a better way.

And I finally (thank god for the Internet & Google!) found the Net::Telnet module.

Installed it from CPAN, and got it up and functioning inside of an hour. I was able to copy a lot of the Net::FTP code (find random image…) right into this new script, and all was well.

One thing I did have to mess around with was the login part – this is not as seamless as the Net::FTP module (though I’m probably missing something).

The telnet script, much more than the FTP script, requires one to have actually done the scripted processes via the command line. Little differences crop up.

For example, the FTP script pulled back – just using “ls [image directory]” all the images into a straight-into-an array manner.

With the telnet script, I had to do a “ls -1 [image directory]” (to get single column listing) and returned all elements with a line feed following (like STDIN). So I had to chomp the selected image to remove this.

In addition, the directory listing – at least on my host – returned, as the last element – the shell cursor (i.e. “[$bash 2.0.1]#” or what have you). So I had to use the pop() command to remove the last element.

I’m not complaining, but it does seem as though the Net::Telnet module is not as generic as the Net:FPT module – or maybe it’s that telnet is not as generic as FTP.

Whatever. It’s done. Little bit of work (a couple of times) and I learned a bunch.

That’s the bonus of Blogger – you’re forced to learn to advance.

I’m cool with that.