Category Archives: Programming

Happy birthday Dancer!

Today marks two years to the day since the first version of Dancer hit CPAN!

According to the BackPAN, Dancer-0.9003.tar.gz hit CPAN on 07-Aug-2009.

I think you’ll agree we’ve come a long way since then, thanks to the awesome community and user base built up around the project since then.

In these two years, we’ve had countless valuable contributions from a large list of contributing users (see the list on the about page), gathered over 300 watchers on GitHub, had 84 people fork the repository on GitHub, had 620 pull requests submitted… amazing stuff.

Continue reading Happy birthday Dancer!

Renaming MP3s based on ID3 tags with Perl

As mentioned in my previous post on retagging MP3s by filename, I have a fairly large music collection, and prefer to keep it well organised.

I like the filenames used to always follow the same pattern, so I wrote mp3-rename, a Perl script to rename them based on the filename.

It takes a directory name as an argument (if not provided, it will operate upon the current directory). It will find all the MP3 files within that directory, extract information from the ID3 tags, then display a table showing the renames it will make if you tell it to go ahead, then ask for confirmation.

An example in action:


[davidp@supernova:~]$ mp3-rename /[...]/Rob\ Costlow\ -\ Woods\ of\ Chaos/
The following renames will be performed:
01 - Meant to Be.mp3    -> 00 - Meant to Be - Rob Costlow.mp3                                                           
02 - Reflections.mp3    -> 00 - Reflections - Rob Costlow.mp3                                                           
03 - Semester Days.mp3  -> 00 - Semester Days - Rob Costlow.mp3                                                         
[...]

Review the above renames to check the info is correct.

Type 'yes' to go ahead: ?>

(Some lines omitted for brevity)

It uses CPAN modules to do most of the work, including File::Find::Rule to find matching files to work on, Music::Tag to handle the tag processing, and Term::ReadKey to find out the terminal size.

Retagging MP3s by filename with Perl

I have a fairly large music collection in MP3s, and I like my files to be sensibly named and tagged.

One of the tools I use to do that is a Perl script I wrote named retag-by-filename, which allows you to provide a regular expression with named captures (so requires Perl 5.10 or later), and uses that to retag a bunch of MP3 files.

An example of it in use:


[davidp@supernova:~]$ ls -1 /shared/music/Complete\ Albums/Oasis\ -\ The\ Masterplan/ | head -3
01 - Acquiesce - Oasis.mp3
02 - Underneath The Sky - Oasis.mp3
03 - Talk Tonight - Oasis.mp3

[davidp@supernova:~]$ ./retag-by-filename --dry-run \
  --pattern="(?<track> \d+) \s - \s (?<title> .+ ) \s - \s (?<artist> .+ ) \.mp3" \
  /shared/music/Complete\ Albums/Oasis\ -\ The\ Masterplan/*.mp3
[01] Acquiesce by Oasis ()
[02] Underneath The Sky by Oasis ()
[03] Talk Tonight by Oasis ()

The --dry-run option shows the details of each track, but doesn’t actually update the tags. The --pattern option supplies the regular expression to match against filenames; you’ll use named captures named track, title, artist and comment to capture the appropriate parts. (In the example above, there is no comment to match.)

Thanks to the awesome power afforded by using modules from CPAN (Music::Tag and Getopt::Lucid), the actual script is 37 lines of code.

Backing up Google contacts/calendar etc

I recently followed a discussion on Twitter after @thomasmonopoly‘s Google account was blocked for unknown reasons, denying him access to the data he’d entrusted Google with.

I casually mentioned that entrusting Google to store all your data without having backups yourself is a bad idea, and @jmrowland enquired as to how you can back up stuff you create “in the cloud” (using Google).

I figured I should share the Perl script I’m currently using to back up my Google contacts, calendar and Google Reader subscriptions, so I’ve uploadedbackup-google-stuff on GitHub.

As I only wrote the script for my own use it’s quite basic and perhaps not particularly user-friendly, but I thought it only fair to share it; if people are interested in it, I may extend it somewhat. I’m fairly sure there are other “backup your Google account” solutions already out there already, though.

Of course, backing up mail from Gmail is trivial as they offer IMAP access; I don’t rely on Gmail so I’ve not bothered with that myself.

EDIT: I’ve seen Backupify recommended as a good solution for backing up your stuff from Google.

Easy profiling for Dancer apps

Today I released Dancer::Plugin::NYTProf, which provides easy profiling for Dancer apps, powered by the venerable Devel::NYTProf.

Using it is simple – load the plugin in your app:

use Dancer::Plugin::NYTProf;

Then, use your app as normal, then, to view the profile data, point your browser to /nytprof (e.g. http://localhost:3000/nytprof, and you’ll get a list of profile runs (each request is profiled individually):

Select the profile run you wish to view, and nytprofhtml will be invoked behind the scenes to generate the HTML reports, which will then be served up, and you’ll be looking at the helpful Devel::NYTProf reports, to see where time was spent processing your request:

Early days yet, and a lot of room for improvement, but in my testing, it works.

Things I’d like to add when time permits:

  • The ability to exclude Dancer internals from the profiling (if I can find a clean way to do so)
  • The ability to enable profiling only for certain requests – for instance, providing a pattern to match the request URLs you want to profile
  • The ability to customise the URL at which profiling reports are served up
  • Check for sane behaviour if prefixes are in use

Feedback welcome!

HTML::Table::FromDatabase 1.00 released with row_callbacks feature

I just released version 1.00 of HTML::Table::FromDatabase, with a new row_callbacks feature.

You could already declare callbacks on a cell-level basis, so you could say, format monetary values appropriately, round numeric columns, turn URLs into clickable links etc. Now, you can also declare a callback which receives an entire row as a hashref, which it can modify as needed.

An (admittedly somewhat contrived) example from the documentation:

my $table = HTML::Table::FromDatabase->new(
    -sth => $sth,
    -row_callbacks => [
        sub {
            my $row = shift;                                                                                 
            if ($row->{name} eq 'Bob') {
                # Hide this row
                $row = undef;
            } elsif ($row->{name} eq 'John') {
                # John likes to be called Jean these days:
                $row->{name} = 'Jean';
            }
        },   
    ],       
);

I decided to bump the version to 1.00 for the sake of anyone who considers 0.x versions to be unready for production use; this module has been about since 2008 and is working well in production use for me.

The Dancer release that will get you hooked!

Sawyer X wrote up a good post on version 1.3050 of the Dancer Perl web framework being released – "The Dancer release that will get you hooked!".

The addition of extra hooks, along with support for plugins to create hooks, heralds additional flexibility and power for your Dancer apps.

Dancer itself now provides various new hooks you can use to customise its behaviour, including before_deserializer, before_file_render, before_error_render, before_template_render, before_layout_render, before_serialization
– see the Dancer::hook() documentation for the full list. Plugins can register their own hooks, which your code can then make use of.

Props go to Franck Cuny for the implementation, and JT Smith of Plain Black for pushing for this feature and working with the Dancer team in designing the implementation.

Dancer 1.3050 also includes various bug fixes and improvements – see the CHANGES file for a full list.

Bot::BasicBot::Pluggable::Module::GitHub

We have an IRC bot in the #dancer IRC channel powered by Bot::BasicBot::Pluggable, and I recently wrote some new features as a distribution of modules which I plan to release to CPAN soon.

Until then, you can see the code in the Bot::BasicBot::Pluggable::Module::GitHub repository on GitHub.

There are two modules so far:

EasyLinks

Bot::BasicBot::Pluggable::Module::GitHub::EasyLinks recognises certain elements within discussions on IRC and provides responses containing titles/URLs to see the corresponding entity, for instance:


<someuser> I'm just working on Issue 42 now
<bot> Issue 42 (Issue Title - Issues - sukria/Dancer - GitHub) - https://github.com/user/project/issues/42

<someuser> I've just submitted PR 517, anyone want to merge it?
<bot> Pull request 517 (Pull request title - Pull Request - GitHub) - https://github.com/user/project/pull/517

<someuser> What do you think of commit 0d2752 then?
<bot> Commit 0d2752 (Commit message summary here) - https://github.com/user/project/commit/0d2752...

PullRequests

Responds to a !pr command, reporting the number of open pull requests, either for whatever project is specified as the default for that channel, or a specific project can be named. For instance:


<someuser> !pr user/project
<bot> Open pull requests for user/project : 5 pull requests open (usera:3, userb:2)

I plan to add more features before releasing the first version to CPAN; in particular, I’d like to add commit hook support, so the module could spawn a trivial webserver to listen for hook triggers from GitHub, and announce commits.

As always, contributions would be welcomed.