More Flexible Firefly Smart Playlists with Perl, sqlite3 and m3u

I use Firefly (previously called mt-daapd) as a media server for my Roku Soundbridge. It has a feature called ‘Smart Playlists’ that dynamically create playlists based on certain criteria, but they aren’t that powerful - they don’t support sorting or other more advanced query features.

Fortunately, underlying Firefly is a sqlite database, which can be queried using standard SQL syntax. This enables a technique of creating static playlists that are automatically re-generated periodically instead.

The prerequisites for the following technique are:

The three commands that follow will create a standard .m3u playlist with the top 100 most-played songs from Firefly’s database, and another playlist with all the non-Podcasts added in the last month, ordered by the time they were added. Neither of these are possible using Firefly’s query language.

sqlite3 /var/cache/mt-daapd/songs3.db 'select path from songs order by play_count desc limit 100' | perl -nle 'require File::Spec; $_ = File::Spec->abs2rel($_, "$PLAYLIST_DIR"); print;' > "$PLAYLIST_DIR/Most-played songs.m3u"

MONTHAGO=$(perl -e 'use Date::Calc::Object qw(:all); $date = Date::Calc>now(); $date += [0,-1,0,0,0,0]; print $date->mktime();')

sqlite3 var/cache/mt-daapd/songs3.db "select path from songs where genre!='Podcast' and time_added > $MONTHAGO order by time_added desc" | perl -nle 'require File::Spec; $_ = File::Spec->abs2rel($_, "$PLAYLIST_DIR"); print;' > "$PLAYLIST_DIR/Music added in last month by most recent.m3u"

(obviously, if you use these, you’ll need to alter paths to suit, make sure the correct Perl modules are installed, remove line breaks to make it easier to read, etc.)

Firefly will read these .m3us if configured correctly during its next rescan, and use them as it would any other playlists. You can force a rescan with the following wget command:

wget --delete-after -q --http-user noone --http-password yourpasswd "http://localhost:3689/config-update.html?action=rescan"

Although not fully dynamic (they are not generated on request from the Soundbridge), if these commands are called from cron or similar, the playlist can be kept up-to-date ’enough’.


Paul, you're right! I don't use this script any more so I can't say how this crept in - but thanks for spotting it.
Thanks for this reference! One minor correction that I would suggest is that if one is actually using $PLAYLIST_DIR to store the playlist location, then the Perl expression used to convert the absolute paths to relative paths should be set off in double quotes with all the enclose double quotes escaped with a backslash and all the dollar signs except for $PLAYLIST_DIR. Otherwise the base directory gets passed as literal "$PLAYLIST_DIR" rather than being substituted by the shell.
Nice feat! I can't wait to try that out. I've found the smart playlists really nice, but the lack of sorting/limiting results seems to be a growing pain in the neck day by day. This seems to be a quite nice way out.
I love my Soundbridge. Simple, well designed, robust, decent quality audio - pretty much says what it does on the tin. About the one minor niggle is that it can't fast-forward/rewind inside tracks. That's not as much of an annoyance as you might at first think. I can't comment on iTunes, but the linkage between mt-daapd and the Soundbridge is pretty much rock solid - and it's going through two Wi-Fi bridges :)
I have always been curious about the Soundbridges - Are they good? I have mt-daapd running for iTunes, but it doesnt find the server very often...