I sat on this one while as I was waiting for this patch. It was merged but never released. Ah well!

This is a very simple python script, which takes your MusicBrainz username as the only command-line argument.


import sqlite3
import musicbrainzngs
import getpass
import os
import sys
import time

if len( sys.argv ) == 1:
    raise Exception( 'No username specified' );

username = sys.argv[ 1 ]
password = getpass.getpass( 'MusicBrainz Password: ' )

musicbrainzngs.set_useragent( 'bricas-sync-ratings', '0.01', 'brian.cassidy@gmail.com' )
musicbrainzngs.auth( username, password )

con = sqlite3.connect( os.path.expanduser( '~' ) + '/.config/banshee-1/banshee.db' )
con.row_factory = sqlite3.Row
cur = con.cursor()

cur.execute( 'SELECT MusicBrainzID, Rating FROM CoreTracks WHERE MusicBrainzID IS NOT NULL AND Rating > 0' );

ratings = {}
row   = cur.fetchone()
count = 0
while row != None:
    count  = count + 1
    rating = row[ 'Rating' ]
    mbid   = row[ 'MusicBrainzID' ]

    ratings[ mbid ] = rating * 20

    if count % 100 == 0:
        musicbrainzngs.submit_ratings( recording_ratings = ratings )        
        ratings = {}
        sys.stdout.write( "count: {}\r".format( count ) )
        time.sleep( 1 )

    row = cur.fetchone()

musicbrainzngs.submit_ratings( recording_ratings = ratings )
print "count: {}".format( count )


I really love the MusicBrainz project. I use their Picard tagger all the time.

I also have an unfortunately complex setup due to the fact that I want to sync all of my music to my iPhone. The current incarnation of this is a Windows 7 VM and a shared folder so I can use Banshee in Ubuntu, and iTunes on Windows with the same folder as the source of my files.

In order for this to work properly, all of my music, for one, needs to be something other than ogg (what a PITA, seriously, Apple), and all of the filenames need to be Windows-safe. Picard makes the latter very easy with its renaming features.

One of the unintended side-effects of doing this is that it will rename all of my files to the name of the track in the MusicBrainz database (NB: directories were left unchanged). This means any differences from the original filename (spelling, capitalization, etc) will mess up my Banshee library.

Read More

This is a short note, which will serve as a reminder, and hopefully help other people who arrive here via the oracle.

If you happen to be running Ubuntu 10.04 LTS, with Trac 0.11 (which can be installed from the canonical repositories), and you decide you want to upgrade Subversion to 1.7 — you will encounter a problem.

One way to fix it, besides not upgrading things that weren’t broken in the first place, is to patch Trac.

I found this changeset, 10833, which is a commit against Trac 0.12, and adapted it for use with 0.11.

--- svn_fs.orig.py        2009-11-23 18:29:48.000000000 -0400
+++ svn_fs.py        2011-12-16 11:30:20.000000000 -0400
@@ -894,21 +894,31 @@
             path = _from_svn(path_utf8)
             base_path = _from_svn(base_path_utf8)
             base_rev = change.base_rev
+# SVN 1.7 FIX
+            action = getattr(change, 'action', None)
             # Ensure `base_path` is within the scope
             if not (_is_path_within_scope(self.scope, base_path) and
                 base_path, base_rev = None, -1
             # Determine the action
-            if not path:                # deletion
-                if base_path:
+# SVN 1.7 FIX
+#            if not path:                # deletion
+#                if base_path:
+            if not path and self.scope == '/': 
+                action = Changeset.EDIT # root property change 
+            elif not path or action == repos.CHANGE_ACTION_DELETE: 
+                if path:            # deletion 
                     if base_path in deletions:
                         continue # duplicates on base_path are possible (#3778)
                     action = Changeset.DELETE
                     deletions[base_path] = idx
-                elif self.scope == '/': # root property change
-                    action = Changeset.EDIT
+# SVN 1.7 FIX
+#                elif self.scope == '/': # root property change
+#                    action = Changeset.EDIT
                 else:                   # deletion outside of scope, ignore
             elif change.added or not base_path: # add or copy

NB: The file on my system was located at /usr/share/pyshared/trac/versioncontrol/svn_fs.py

I’m not entirely unsure if this is 100% correct, but it works for me. I hope it helps you too.

It’s been online for a couple of weeks now, but if you haven’t already seen it — check out the CPAN::Changes Kwalitee Service. Special thanks to Franck Cuny for hosting and feeding this beast!

The site tracks the overall CPAN::Changes spec conformance as well as a break down by author and distribution. For ease of tracking, we offer feeds for both of these facets as well as a global “recent releases” feed.

If you take a closer look at that feed, any non-conforming releases will indicate that fact with an error message. All of the releases with properly formatted changelogs will have their matching release information extracted and used in the body of the feed entry.

Any suggestions for the service are welcome. The source for the project can, of course, be found on github.

If you visited the site early on, you would have seen that the CPAN had about a 10% conformance rate. These days we’re hovering around 30%. Unfortunately, there hasn’t been a mass acceptance of the spec; I’ve just relaxed the date parsing rules.

I had a number of people question the use of W3CDTF dates when a number of existing distributions use “scalar localtime”-style dates. Since I can easily discover those dates, I’ve changed CPAN::Changes (release 0.09) to parse them and convert them to W3CDTF dates. I will continue to promote the use of W3CDTF dates and the CPAN::Changes tools will continue to output dates in that format only.

At the same time I’ve tightened up the validation of those W3CDTF dates (release 0.10) to get rid of any false positives I was seeing.

Happy changelogging!

In talking about changelogs, I thought it might be good to take a snapshot of what is out there. I whipped up a quick script to parse through my minicpan and pull out filenames that looked like “change*” (case-insensitive) from the root directory.

21545 distributions were parsed. *

Out of those, 2305 (10.7%) had no files matching that regex. This is an unfortunate stat, but one could posit a couple of reasons: 1) the author simply neglected to include it 2) the author chose to use a different naming convention; both are plausible. For the latter, I’ve seen other files such as NEWS or even a pod file (generally within the lib/ structure) in a few distributions.

The most common filename was, of course, “Changes” with 17138 (79.5%) distributions falling under that naming. Second to that was “CHANGES” — 1016 (4.7%) distributions use that. In third place was “ChangeLog” at 847 (3.9%) distributions.

As you can see, the drop off after the top spot is significant. There were a few other variations worth mentioning: “CHANGELOG” (136), “Changelog” (70), “Changelog.ini” (64), “Changes.ttl” (58), “Changes.xml” (48) and “Changes.txt” (30).

It seems fair to say that to achieve consistency, we should adopt “Changes” as the standard name for CPAN distribution changelogs. This is certainly the path of least resistance as nearly 80% already follow this notion. Please feel free to voice your opinion in the comments below!

In my next post, I will do some further analysis on the actual content of these changelogs.

* Note: I pulled out all files that matched, thus some distributions returned more than one file. The total of the filenames comes to 21888, which gives us a small margin of error.

The topic of Changes files has once again come into focus — see Dave Rolsky’s posts here and here.

I posed a question a few years back about machine parsable Changes files. A number of people picked up on this and some further conversations ensued:

So, what happened? Well, not much.

I don’t think there’s a single person that could agree on what should be in a Changes files. Some people wanted to argue about the serialization format (YAML vs Text vs XML vs …). Some people thought that things were “too structured”, some “not structured enough.” This kind of back-and-forth was inevitable — everyone has an opinion.

At my own peril, I’ve decided to re-tread this old ground.

To that end, I’ve uploaded CPAN::Changes to CPAN (source here). What’s inside:

  1. CPAN::Changes::Spec - A specification document. I’ve attempted to codify a number of standard practices seen in changelogs included in CPAN distributions. It’s a light read with only a few rules, but it gives some consistency to the file’s structure.
  2. CPAN::Changes (and ::Release) - An API to read and write Changes files. Once you have a predictable structure, you should be able to play around with it in a programmatic fashion. I can envision integration with distribution building tools, SCM tools, and CPAN clients.
  3. Test::CPAN::Changes - A simple module to help automate the validation of Changes files. This is probably most useful during release testing to make sure you’re sending a spec-conforming changelog to CPAN.

I’ve deliberately kept the spec simple, taking what’s already out there and applying some basic rules. It’s open for comments — let me know what you think!

After performing a routine upgrade of my CPAN modules on my $work machine, I noticed that I was prompted to configure CPAN for the first time after I attempted to load the CPAN shell again.

Obviously I had already done all of that so I had to figure out what had changed. I remembered having installed only a couple new modules, including File::HomeDir.

Browsing its Changes file shows:

Moving the FreeDesktop driver to prod

My operating system is Ubuntu 10.04, which apparently means that File::HomeDir will use these new FreeDesktop rules. The big change is that the default data dir is no longer your home directory, but ~/.local/share/

The simple fix was to move my .cpan dir to ~/.local/share/. From then on, everything worked as per usual. This will also affect any other apps that use File::HomeDir to locate your data dir, including Padre.

Ever looked back at something you’ve worked on and thought: “Gee, it’s too bad that project didn’t get to it’s ultimate goal, but, I’ve learned a lot from it.” I have one of those projects. Such is the world of technology, your toolset is constantly evolving and shape-shifting; even “The Next Big Thing” can become obsolete. We move on to the next “Next Big Thing.”

One such area in the Web Developer’s toolset is “Search.” I’m sure we can all relate to the experience of our first textbox with some behind-the-scenes code doing SQL “SELECT … LIKE” statements. Perhaps at first it was raw DBI calls; maybe moving on to an abstraction layer (ORM and whatnot) shortly thereafter. Here’s where things get interesting.

What happens when this is no longer Good Enough(tm). Google being essentially ubiquitous, people expect to plunk some words in the box and magically get what they want out the other side. I put in “Cat Hat” — why didn’t it give me “Cat in the Hat”? Okay, no problem. We can do some field and query normalization; removing stopwords, add term parsing … wait, wait wait. There has to be prior art for this.

In 2004, the options are somewhat limited as far as Free/Open Source search software goes. Especially in Perl land. Swish-e looks pretty neat. We actually did some prototyping with it. It was definitely a step ahead of plain old SQL. Plucene came on the scene. Unfortunately, it’s poor performance was a bit of a non-starter for us. The fact that it was modeled after the Lucene Java library, however, caught my eye.

I wanted to harness their project and its community, and bring it into our little Perl world. Luckily for me, someone else had already started down that road. The Lucene Web Service was a project by Robert Kaye, sponsored by CD Baby, which allowed users to talk to Lucene via an XML-based web service. After using it for a while, we developed some patches for bug fixes and enhancements. Because of our momentum with the project, we were eventually given total control over its development.

We attempted to strengthen the project by hooking into some existing standards. We leveraged the Atom Publishing Protocol as an analogy for dealing with indexes and documents. Search results were returned as an OpenSearch document. A document’s field-value pairs were listed in the XOXO microformat. Creating a client for this setup meant a bunch of glue between the existing components (XML::Atom::Client and WWW::OpenSearch).

Almost in parallel, the Solr project emerged. Similar idea, much more support behind it. In the end, our idea never got very far, and Solr has turned out to be a fabulous product — which we now use.

To this end, the Lucene WebService website will (finally) be shutting down in about a week’s time. I’ve moved the pertinent code and wiki data to github in case anyone wants it. I still think it has some niche applications, but without some serious revamping of the java code, it will likely just rot.

At least it’s a project that has led me to bigger and better things.

Padre 0.54 introduced a couple of project-specific settings, one for Perl::Critic and another for Perl::Tidy. As the maintainer of the Perl::Tidy plugin, it was only natural that I should implement support for this new feature.

Unfortunately, it wasn’t immediately obvious to me how I might get at this info. With Adam’s guidance, I was able to write the following:

my $tidyrc = $self->current->document->project->config->config_perltidy;

It’s a mess of chained method calls, but, it pretty clear that we’re getting the current document’s project-related config, if it exists.

Here’s a screenshot of the new version of the plugin in action.

Grab version 0.09 from CPAN now.

I haven’t bothered to post anything in the last five months. With Christmas just around the corner, I figure this is as good a time as any to play catch up.


  • A new release of this plugin — changes made mostly by other people.


  • Rather than using a base url for the data, you can now specify a number of url templates. This makes the module actually useful. Thanks to Chris Prather for working through this with me.


  • A couple of releases with various refactoring bits and bug fixes. The folks at software77.net now produce a data file specifically for this module. I will ship an updated copy with every release. Refactoring this code has been pretty satisfying, though there are some parts of the module API which I detest but I will be unable to modify them.


  • Various bug fixes thanks to some testing with a large dataset from Doug Moore and sixteencolors.net


  • Released version 0.18, which prefers YAML::XS over any other YAML parser. This created a number of issues with the HTML::FormFu crowd as existing parsers allowed this sort of syntax “auto_id: %n” — whereas YAML::XS complains about an exposed percent sign. The easy fix is to wrap the string in quotes “auto_id: ‘%n’”


  • Fixed a nasty bug due to a missing my() which randomly broke the module on some platforms.


  • A tiny patch for max_height included in this release. This still has some pending issues in RT — though I have a hard time justifying spending any time on them as I don’t use this module at all.


  • Apparently, this module was basically broken. Fixed thanks to a supplied patch.


  • Another kind user supplied some patches/info to support mod_perl and fully qualified template names.


  • Removing use of UNIVERSAL->import from these module. Not even sure why it was there to begin with.


  • A couple of release of this module. Includes some bug fixes, feature additions and Solr 1.4 compatibility.

Remove auto_install from my dists

  • Although, as I understand it, auto_install now works in newer versions of Module::Install, I’ve decided to remove it from my dists to avoid any issues.

See you next year.