Customization…. one of the many reasons Linux is my primary desktop :)
Linux, Mac OSX, OS, Windows, humor No Comments »Can you do this on your favorite operating system?
“Laugh it up fuzzball!” - Han Solo
Listen to this podcast
Can you do this on your favorite operating system?
“Laugh it up fuzzball!” - Han Solo
Listen to this podcast
If you’ve ever tried to back up your Flickr account or download the public Flickr photos of other users, then your options were pretty limited on Linux. After trying and failing to get FlickrDown to work under wine, I decided to write my own… in perl
The various Flickr API’s on CPAN are incomplete with respect to obtaining the list of public/friends photos. I had to use XML::Parser::Lite::Tree::XPath to extract the photos from each Flickr page.
By default, we obtain the largest photo available (orginal -> large -> medium -> small), populate the EXIF comments field with the Flickr photo title, description and url. We verify the file type with File::MimeInfo::Magic and change/add the file extension as necessary.
During testing I received numerous duplicate files which were mostly resolved by adding a rudimentary duplicate file checker.
It should work on just about any platform that Perl does.
Thoughts?
FlickrDownload.pl
FlickrDownload.pl
use strict;
use warnings;
use Digest::MD5 qw(md5_hex);
use Config::Simple;
use Image::ExifTool;
use File::MimeInfo::Magic qw(mimetype extensions);
use Flickr::API::Photos;
use Flickr::Person;
use Getopt::Std;
use HTML::Entities ();
use File::MimeInfo::Magic;
use IO::Scalar;
use LWP;
use Tie::File::AsHash;
use XML::Parser::Lite::Tree::XPath;
##############################
my $cfg = new Config::Simple(‘FlickrDownload.ini’);
my $user_name;
my $id;
my $email;
my %arg_options;
my $photo_directory;
my $found;
getopts(‘e:i:u:’, \%arg_options);
$user_name = $arg_options{u};
$id = $arg_options{i};
$email = $arg_options{e};
my $flickr_api_key = $cfg->param(‘Flickr.API_KEY’);
my $flickr_secret = $cfg->param(‘Flickr.API_SHARED_SECRET’);
my $flickr_email = $cfg->param(‘Flickr.email’);
my $flickr_password = $cfg->param(‘Flickr.password’);
##############################
sub decode_html {
my $string = shift;
my $new_string = HTML::Entities::decode($string);
if ($string ne $new_string) {
$new_string = decode_html($new_string);
}
return $new_string;
}
##############################
my $flickr_person = Flickr::Person->new( {
api_key => $flickr_api_key,
email => $flickr_email,
password => $flickr_password
} );
if ($user_name) {
$found = $flickr_person->find( { username => $user_name } );
} elsif ($email) {
$found = $flickr_person->find( { email => $email } );
$user_name = $flickr_person->username();
$found = $flickr_person->find( { username => $user_name } );
} elsif ($id) {
$found = $flickr_person->id( {id => $id} );
$user_name = $flickr_person->username();
$found = $flickr_person->find( { username => $user_name } );
}
if ( $found ) {
my $page_num = 1;
my $more_pages = 1;
my $api = $flickr_person->{people_api}->{api};
$photo_directory = $cfg->param(‘Photos.directory’) . "/" . $user_name;
$api->{api_secret} = $flickr_secret;
my $flickr_photos = Flickr::API::Photos->new(
$flickr_api_key,
$flickr_email,
$flickr_password);
unless (-d $photo_directory) {
mkdir $photo_directory
or die (‘Unable to create directory "’ . $photo_directory . ‘"’ );
}
# for determine whether we might be downloading a duplicate, we need a hash with
# the MD5 sum & filename. We tie both hashes to a file in the flickr user’s
# directory
tie my %MD5_HASH, ‘Tie::File::AsHash’, $photo_directory . "/.md5s", split => ‘:’
or die "Problem tying %hash: $!\n";
tie my %FILES_HASH, ‘Tie::File::AsHash’, $photo_directory . "/.files_md5s", split => ‘:’
or die "Problem tying %hash: $!\n";
while ($more_pages) {
my $response = $api->execute_method(‘flickr.people.getPublicPhotos’, {
api_key => $flickr_api_key,
user_id => $flickr_person->id,
per_page => 500,
page => $page_num
} );
my $xpath = new XML::Parser::Lite::Tree::XPath($response->{tree});
my @nodes = $xpath->select_nodes(‘/photos/photo’);
if ($#nodes > 0) {
foreach my $node (@nodes) {
my $original_photo;
my $photo_id = $node->{attributes}->{id};
my $photo_hash = $flickr_photos->getInfo($photo_id);
my $photo_title =
$photo_hash->{‘title’}
? $photo_hash->{‘title’}
: "";
my $description =
$photo_hash->{‘description’}
? decode_html( $photo_hash->{‘description’} )
: "";
my %photo_sizes =
map { $_->{‘label’} => $_ }
@{ $flickr_photos->getSizes($photo_id)->{sizes} };
if (exists $photo_sizes{‘Original’}) {
$original_photo = $photo_sizes{‘Original’};
} elsif (exists $photo_sizes{‘Large’}) {
$original_photo = $photo_sizes{‘Large’};
} elsif (exists $photo_sizes{‘Medium’}) {
$original_photo = $photo_sizes{‘Medium’};
} elsif (exists $photo_sizes{‘Small’}) {
$original_photo = $photo_sizes{‘Small’};
} else {
warn "Unable to find url. Skipping photo."
}
printf "name: %s id: %s description: %s\n",
$photo_title,
$photo_hash->{‘id’},
$description;
my $photo_filename = $photo_directory . ‘/’ . $photo_title;
$photo_filename =~ s/\.\w+$//;
# Prepopulating the file extension will allow us to eliminate
# the vast majority of duplicate images by not downloading
# them in the first place.
if (exists $photo_hash->{‘originalformat’}) {
my $extension = $photo_hash->{‘originalformat’};
$photo_filename .= "_" . $photo_hash->{‘id’} . "." . $extension;
} else {
# if we don’t know at this point what format the image file is
# without downloading the image, we can assume it is a jpg
# because the vast majority of the photos are jpg.
$photo_filename .= "_" . $photo_hash->{‘id’} . ".jpeg";
}
if (-f $photo_filename && (stat($photo_filename))[7] > 2048) {
printf "We already have photo %s .. Skipping\n", $photo_title;
} else {
my $FH;
my $request = HTTP::Request->new(GET => $original_photo->{’source’} );
my $response = $api->request($request);
my $md5_sum = md5_hex($response->content);
# since we have downloaded the photo, let’s put the proper file
# extension on it.
if (my $file_ext = extensions( mimetype(new IO::Scalar \($response->content) ) ) ) {
$photo_filename =~ s/\.\w+$//;
$photo_filename .= "." . $file_ext;
}
if (exists $MD5_HASH{$md5_sum}) {
printf "We already have photo %s .. Skipping\n", $photo_title;
} else {
$MD5_HASH{$md5_sum} = $photo_filename;
$FILES_HASH{$photo_filename} = $md5_sum;
open($FH, ">", $photo_filename)
or warn ("Unable to write to $photo_filename.\n" );
binmode $FH;
print $FH $response->content;
close $FH;
# We’re going to use Image::ExifTool instead of the built in
# exif extracted information from Flickr::API::Photos because
# we want to write to the file.
my $exifTool = new Image::ExifTool;
my $info = $exifTool->ImageInfo($photo_filename);
unless ($info->{‘DateTimeOriginal’}) {
if ($photo_hash->{‘dates’}->{‘taken’}) {
my $taken_date = $photo_hash->{‘dates’}->{‘taken’};
$taken_date =~ s/\-/\:/g;
$exifTool->SetNewValue("DateTimeOriginal", $taken_date);
}
}
$exifTool->SetNewValue("Comment", $photo_title . ": " . $description . " " . $original_photo->{’source’});
my $result = $exifTool->WriteInfo($photo_filename);
}
}
}
$page_num++;
} else {
$more_pages = undef;
}
FlickrDownload.ini
[Photos]
# where you want to put the photos
directory=/home/jason/flickr
Listen to this podcast
Back in March 2007, I posted about The Sad State of Mac OSX Printer Drivers. I’m sad to say that little has changed. Even noted computer experts like Leo Laporte seem to be unaware that this is an issue with Apple and the printer manufacturers.
In hour three of Leo Laporte’s The Tech Guy radio show on Sunday 13 January 2008 (episode 422), a caller says she was unable to print to her Canon Pixma printer from her Mac when the printer is on the network. She is able to print when she connects the printer directly to the Mac.
Q Verit - Print server not working
You need to add it as an IP Printer. Then you find out the IP of the Printer and then put that into the Mac’s and other Windows Machine.
The Mac comes with Direct Print drivers, however you need network drivers for that Canon printer. You can use Unix drivers, but it’s not worth it. You’ll probably just want to get a Canon for the mac.
Canon just doesn’t believe that Apple users have network printers that are either connected to a Windows box or a print server.
Listen to this podcast
Sybase has decided that supporting ASE and Open client/Open server (SDK) on the Apple Mac OSX platform is not viable. End of life for all three is 12/31/2009.
ASE End of Life Notice
Open Client End of Life Notice
Open Server End of Life Notice
Thanks to Neal (Sybase Neal) on sybase.public.macosx for pointing this out
Alternatives? For ASE and OpenServer, you will need to migrate to a supported platform (Linux, Windows, etc). For Open Client, you have the option of using FreeTDS, an open source drop in replacement for OpenClient - they even work with ODBC, or using jConnect (a JDBC v4 compliant driver).
Listen to this podcast
Erica Sadun wrote an application, written in Perl, to convert your iPhone backup files into a SQLite3 database:
Here’s a nice way to recover notes from your iPhone without having to mail them to yourself–although it’s not for the faint of heart. Read more at The Unofficial Apple Weblog…
It would be a simple matter to have the data imported in to your favorite DBMS if you prefer Sybase ASE, MS SQL Server, dBASE / xBase, etc.
Listen to this podcast
IBM has a new article by Martin Streicher that explains just how Unix processes are able to multitask.
Speaking UNIX, Part 8: UNIX processes
03 Apr 2007
On UNIX® systems, each system and end-user task is contained within a process. The system creates new processes all the time and processes die when a task finishes or something unexpected happens. Here, learn how to control processes and use a number of commands to peer into your system.
At a recent street fair, I was mesmerized by the one-man band. Yes, I am easily amused, but I was impressed nonetheless. Combining harmonica, banjo, cymbals, and a kick drum — at mouth, lap, knees, and foot, respectively — the veritable solo symphony gave a rousing performance of the Led Zeppelin classic “Stairway to Heaven” and a moving interpretation of Beethoven’s Fifth Symphony. By comparison, I’m lucky if I can pat my head and rub my tummy in tandem. (Or is it pat my tummy and rub my head?)
Lucky for you, the UNIX® operating system is much more like the one-man band than your clumsy columnist. UNIX is exceptional at juggling many tasks at once, all the while orchestrating access to the system’s finite resources (memory, devices, and CPUs). In lay terms, UNIX can readily walk and chew gum at the same time.
This month, let’s probe a little deeper than usual to examine how UNIX manages to do so many things simultaneously. While spelunking, let’s also glimpse the internals of your shell to see how job-control commands, such as Control-C (terminate) and Control-Z (suspend), are implemented. Headlamps on! To the bat cave!
The article provides a wonderful overview with commands you can run to monitor your own Unix (or Linux or even MacOSX) box. Understanding how Unix/Linux/MacOSX works is not always so easy. I can’t stress enough that DBAs need to know the operating system that their databases reside on.
This was reported on Digg, Slashdot and a myriad of other sites.
Listen to this podcast
One man was so determined to finish his project, he broke into Cupertino every day, to code for them without pay or permission. Six months later, he sneaked the app into the final version of Mac OS 9, without Apple ever knowing.
Listen to this podcast
So you bought a brand spanking new Apple iBook laptop. The latest and greatest of everything. You fire up Microsoft Office and hit the print button sending your 10 page document to your new Canon Printer. Nothing happens. You turn off the printer and turn it back on. Hit print. Nothing happens.
Unfortunately this is all too common when printing from OSX to a printer hosted on a Microsoft Windows box. The printer manufacturers create wonderful printer drivers if you hook up the printer directly to your Macintosh or have it connected to another Mac. If the printer is hooked up to a Windows box, too bad.
Most printer manufacturers are too lazy and just don’t care about mixed environments. Sure, you can go with a third party printer driver, but why should you have to pay another $60 just to print FROM ONE COMPUTER with no guarantee from the third party that the driver will really work? Apple needs to push the printer manufacturers to allow for printing to remote printers (Windows Shared Printers, IPP printers, etc). At best this is blatent neglect from the printer manufacturers and Apple itself.
Mister Jobs, please please prove you have the cojones to stand up for us with the printer manufacturers!
The official response from Canon? Canon recommended buying a second printer.
Listen to this podcast
Recent Comments