Recent uploads from my Flickr photostream...

Archive for January, 2009

Retagging audio tracks based on filename

I had some audio tracks which weren’t tagged, but did have filenames containing the artist, title etc, so I whipped up a quick Perl script to sort them out – retag-by-filename.pl.

It takes a regular expression with named captures for track, title, artist and comment, and sets the tgs on the file as appropriate.

It makes use of Music::Tag to do the actual tagging and Getopt::Lucid to read the options supplied, and requires Perl 5.10.0 for named regex captures (and ’say’).

A --dry-run option allows you to check that the filenames are being parsed correctly by your regex before actually writing tags.

See retag-by-filename.pl for the full details.

Easy CLI option parsing with Getopt::Lucid

I often write Perl scripts which need to read options given on the command line. Normally I turn to the venerable old Getopt::Long which does the job.

However, I was writing a script which needed to be able to accept only certain parameters, which were mostly optional, and also take a list of filenames. I wanted this to be possible in any order, e.g.:

myscript --foo=foo --bar=bar file1 file2
myscript file1 file --foo foo

Getopt::Lucid makes this all pretty easy, and also makes the code pretty self-documenting, too. Straight from the documentation, showing the various types of parameters it can parse:

@specs = (
    Switch("version|V"),
    Counter("verbose|v"),
    Param("config|C"),
    List("lib|l|I"),
    Keypair("define"),
    Switch("help|h"),
);
 
$opt = Getopt::Lucid->getopt( \@specs );
 
$verbosity = $opt->get_verbose;
@libs = $opt->get_lib;
%defs = $opt->get_define;

A real-world example,from one of my scripts which handles ID3-tagging:

# The options we can take - these correspond to the name of the tag that
# they'll set:
my @options = qw(track title artist album comment);
 
my @option_specs = (
    Getopt::Lucid::Switch('verbose|v'),
    map { Getopt::Lucid::Param($_) } @options,
);
my $opt = Getopt::Lucid->getopt(\@option_specs);
 
my @tags_to_set = grep { $opt->{seen}{$_} } @options;
my @files = @{ $opt->{target} };
 
if (!@tags_to_set) {
    say "Nothing to do.  Use one or more of the options:\n" .
        join ', ', map {'--'.$_} @options;
    exit;
}

(The script then goes on to loop over all files, and use Music::Tag to set the ID3 tags requested).

Disabling reply-all? How stupid!

Apparently, Neilsen has disabled reply-all for all their Outhouse users, to “eliminate bureaucracy and inefficiency”.

What an incredibly stupid idea. Removing a very useful feature, just because a few people use it incorrectly? Stupid, stupid, stupid.

If people were CC’d on a mail you receive, then that mail was relevant to them, and contained info they needed. There’s a good chance your reply will also be something they should read; if that’s the case, you hit Reply All. If your reply is only relevant to the original author, just hit Reply. Really not that hard, is it?

Whining entitlementism

Just read a post likening shutting down websites to eviction (see also the follow-up here).

I’m saying that, like a real eviction, there should be practices in place. When you open your doors to hosting user content, you should have rules in action that, unless it’s a complete and total fire sale and you have no hope of even staying open that long, then you should be required, yes by law, assholes, to make the data available to customers for an extended period of time.

I’m sorry, but I think that’s a terrible idea. If a site or hosting service is free, you have no rights to demand things from it. If the site/service owners cannot afford to continue running it, or do not want to do so, it’s their prerogative. It would be nice and polite of them to do whatever they can to help you retrieve any content you had submitted there, but bollocks should it be a legal requirement.

Making laws like this will achieve one thing: dissuading people from knocking together valuable sites, for fear of the hassle of having to follow these laws if they ever want to shut it down. It’s not at all uncommon for sites which are huge these days to have started out as a one-person operation hacked together in their spare time.

At the end of the day, if a site/service becomes unavailable, the very most you should be legally entitled to is a refund of the amount you paid (pro-rata for the remaining paid-up service term). Morally, if the site owners are able to keep the data about for a while for people to download, that’d be a very nice gesture, but should certainly not be required.

The author of the posts above cites a few “heartbreaking” comments by people who used AOL Hometown, which shut down. AOL provided four week’s notice of the closure. Who the hell treats data placed online as their only copy? I’ve uploaded a fair number of photos to Flickr and Facebook, but the originals stay on on my hard drive (RAIDed and backed up to another drive also). If Flickr or Facebook had to shut down for whatever reason, I’d not have lost anything, and wouldn’t consider them responsible for my data.

Easy file finding with File::Find::Rule

Recently I found File::Find::Rule on the CPAN, and I’m impressed how easy it makes it to get a list of files to work on.

A fairly common way to do this in Perl would be something like:

my $dirh = new DirHandle($somedir);
while (my $entry = $dirh->read) {
    # Skip hidden files and directories:
    next if ($entry =~ /^\./ || !-f $entry);
 
    # Skip if it doesn't match the name we want:
    next if ($entry !~ /\.txt$/);
 
    print "Found: $somedir/$entry\n";
}

File::Find::Rule makes things rather easier:

my @files = File::Find::Rule->file()->name('*.txt')->in($somedir);

Various conditions can be chained together to find exactly what you want.

Another example, showing combining rules with ->any() to find files matching any of those conditions:

# find avis, movs, things over 200M and empty files
my @files = File::Find::Rule->any(
    File::Find::Rule->name( '*.avi', '*.mov' ),
    File::Find::Rule->size( '>200M' ),
    File::Find::Rule->file->empty,
)->in('/home');

There’s plenty of other ways to do this, but I think File::Find::Rule gives a way to clearly and concisely state what you want and get the job done.

Favourite new Perl features

I’ve been starting to make use of the new features introduced in perl 5.10 recently (after being constrained by my main dev environments still running perl 5.8.8, and not having the time to upgrade).

My favourite features so far are:

The smart match operator

The new smart-match operator, ~~, is a great example of DWIM.

A few examples:

if (@a ~~ 'foo')  # list contains at least one item equalling 'foo'
if (@a ~~ /foo/) # list contains at least one item matching /fo+/
if (@a ~~ @b)   # lists contain same values

That’s just a brief overview; there’s plenty more documentation

say

Not a big change, but the new say keyword acts just like print, but adds an implicit newline to the end – so say 'Hello'; is just the same as print "Hello\n";

It’s more useful in cases where you would have had to add parenthesis to get correct precedence – something like: print join(';', @foo) . "\n"; can now be written more concisely as just say join ';', @foo;.

Switch (given) statement

given ($foo) {
    when (/^abc/) { abc(); }
    when (/^def/) { def(); }
    when (/^xyz/) { xyz(); }
    default { die "Unrecognised foo"; }
}

Defined-or

// is now the defined-or operator.

It's pretty common to use conditional assignments like: $a ||= $b to assign to $a unless $a already has a value. Now you can use $a //= $b to test for definedness rather than truthiness.

Likewise, if ($hash{foo} // $hash{bar}) will be true if either of them is defined (even if they're defined but have a false value).

Named regex captures

Parenthesised sub-expressions in regular expressions can now be given a name, and accessed via the special %+ hash:

if ($foo =~ m{ (?<year> \d{4} ) - (?<month> \d{2}) - (?<day> \d{2}) }xms) {
    say "Year: $+{year}";
}

The features above are my own personal favourites, in no particular order. The full (large) set of changes can be found in the perldelta for 5.10.0.

Lame jokes on Twitter

This evening, just for a laugh, I created a script to post short lame (but funny) jokes to Twitter periodically.

Feel free to follow @lamejokes on Twitter for amusement. It also posts as @lamejokes on identi.ca (or should, now that the account is confirmed…).

Spread the news to anyone that wants amusement ;)

Practicing image manipulation with GIMP

It’s been a while since I’ve done any image manipulation, so last night I randomly decided to play with GIMP (the GNU Image Manipulation Program, basically an open-source alternative to Photoshop, although admittedly not as powerful).
Continue reading ‘Practicing image manipulation with GIMP’

Monitoring Twitter via RSS search result feeds

Want to make better use of Twitter, getting a better signal to noise ratio, spotting tweets about things you’re interested in without having to wade through things you’re not?

Use the Twitter search, and enter terms you’re interested in, seperated by OR (e.g. badgers OR mushrooms OR snakes), then hit search – as you’d expect, you’ll find any tweets mentioning any of the terms you mentioned.

Now, in the top right of the results page, is a “Feed for this query” link – this gives you an RSS feed for this search which you can subscribe to in your RSS reader of choice. Now, you have a feed you can monitor for anything that’s of interest for you, whether that be your personal interests, or your company’s brand and terms related to your target market (e.g. hosting OR domains OR ecommerce etc).

Of course, you could just hand-craft the feed URL, if you’d prefer – it will look like:

http://search.twitter.com/search.atom?lang=en&q=badgers+OR+mushrooms+OR+snakes

It’s easy enough to change that to whatever you want :)

Pastebin Firefox extension

My friend James Ronan has just released a Pastebin Firefox extension, making it even easier to paste code etc to pastebin.com.

As the code by Paul Dixon which powers pastebin.com is Open Source and can be installed on your own server, the extension allows you to provide the URL of your own private pastebin install if you have one – this is ideal for me, as we have a private pastebin setup at work which is often used.

Using the extension is as simple as right clicking and chosing “pastebin my clipboard”, which submits the contents of your clipboard (or highlight buffer) to pastebin, and copies the resulting URL to the clipboard, ready for you to paste on IRC / IM / whatever.
Continue reading ‘Pastebin Firefox extension’


Random photos from my Flickr photostream...