Sam's Blog

Bash-itunes plugin tutorial

Date: Friday, 15 June 2012, 11:03.

Categories: bash-itunes, itunes, cli, bash, shell-scripting, apple-script, tutorial.

In v1.2.0 of bash-itunes, my project to control iTunes from the command-line, I've added plugin support for sub-commands.

This allows you, or anyone else, to add new commands to the basic script without needing to alter the script itself.

Read below the cut for details and a walkthrough of creating a new plugin.

Writing a status plugin

Adding a new plugin in easy enough, you create a bash script in your $HOME/.bash-itunes/plugins/ directory and name it after the subcommand you want to add.

This probably works best with an example, so I'll walk you through creating an itunes status command that displays a summary of the current track, the current playlist and your full library in a mini-dashboard style.

Create the plugins directory

First up, make our plugins directory, at a shell prompt:

$ mkdir -p ~/.bash-itunes/plugins

Create the skeleton of the plugin file

Now we're going to create the skeleton of our plugin, edit the ~/.bash-itunes/plugins/status file, like so:

Code:
#!/bin/bash

PLUGIN_NAME="Status"
PLUGIN_VERSION="1.0.0"
PLUGIN_BRIEF="Displays a dashboard of iTunes status."

function _cmd_status() {
    echo "Do something!"
}

The PLUGIN_NAME line defines the name of the plugin, this doesn't have to be the same as the command, but should probably be related, if only for the sanity of your users.

PLUGIN_VERSION defines the version number of the plugin, at the moment this is only used by the itunes plugins command, but may be used for other stuff in the future, so try to stick with a major.minor.patchlevel numbering convention please.

PLUGIN_BRIEF is a brief one-line description of what the plugin does, this will be displayed with an indent in the plugins list, so it should be kept to 70 characters or less.

The _cmd_status() function is where our new subcommand does its work, it gets called when itunes status is run, and the arguments are the rest of the command-line after the status subcommand. For now we're just going to display a message and nothing else.

Setting these three variables and defining the subcommand function are the only things that the script should do in its main body.

Checking the skeleton plugin works

Now we've created the skeleton of our plugin it's time to check that bash-itunes can find it:

$ itunes plugins Installed plugins: status - Status (1.0.0) Displays a dashboard of iTunes status. $ itunes status Do something!

Accessing bash-itunes internals to "Do Stuff"

So, we have a "working" plugin now, although it doesn't do much, it's time to look into making it really really work.

Plugin files are "sourced" by the itunes command when you perform a matching subcommand. If you're not familiar with what sourcing means, it's more or less like an include in other languages. This process happens any time we need to access meta-data for the plugin, such as when you do itunes plugins. Since it actually executes the script, this is why you shouldn't perform any actions in the main body of the script: those actions will happen every time the plugin is included.

The main benefit of sourcing however is that it runs in the same environment as the main command, meaning it has access to all the internals of bash-itunes, and we're going to make use of this in our status command.

Let's modify our plugin file, changing the _cmd_status() function until it looks like this:

Code:
function _cmd_status() {
    _show_current_track "Currently playing" 0
    _show_current_playlist "On playlist" 1
}

Now if you run itunes status you should see something like:

$ itunes status Currently playing "Horizon" by Funker Vogt, from "Maschine Zeit" (3:31 of 8:06) You've rated this track 100. On playlist "c Synth+Ind" (7:18:19:57) (2264 tracks)

What we've done here is make use of the two bash-itunes internal functions for displaying the current track and current playlist, giving them a custom "preamble" and showing the track verbosely and the playlist briefly.

Obviously, since these functions are internal to bash-itunes, their API may be subject to change, but we can live with that for now.

Also note that the playlist fetch takes quite some time in the current version of bash-itunes (v1.3.0), since it fetches all track data for the playlist, even though we're not using it.

Finally, it also fetches the data from iTunes in two passes rather than a single pass, which isn't very efficient.

These are all things that you could fix if you wanted to do this "for real".

Accessing AppleScript and iTunes to do "new stuff"

So far we've just done a couple of things that bash-itunes already lets you do, although we have combined them into a single command, but next-up we want to display some summary information about the entire iTunes library.

To do this we need to write some new AppleScript to fetch data from iTunes and use the bash-itunes helper functions to run it for us.

Open the plugin file again and change our subcommand function to:

Code:
function _cmd_status() {
    _show_current_track "Currently playing" 0
    _show_current_playlist "On playlist" 1
    local total_tracks=$(_tell_itunes "count tracks")
    local total_playlists=$(_tell_itunes "count playlists")
    echo "The iTunes library contains" \
        $(_pluralize "$total_tracks" "track") \
        "and" \
        $(_pluralize "$total_playlists" "playlist")
}

And, once again, run it:

$ itunes status Currently playing "There Is No God" by Velvet Acid Christ, from "Fun With Knives" (0:31 of 5:15) On playlist "c Synth+Ind" (7:18:19:57) (2264 tracks) The iTunes library contains 4851 tracks and 49 playlists

This time we've created two local variables total_tracks and total_playlists, and used the bash-itunes function _tell_itunes to run our fragment of AppleScript within a tell application "iTunes" block and return the result to store in those variables.

count tracks and count playlists count how many of those types of object are in the iTunes library.

If you wanted to fetch a more complicated data-structure you could look at the _ask_itunes and the _fetch_from_itunes helper functions in bash-itunes, but detailing them is outside the scope of this article.

Our final source

The final source code of our itunes status plugin should look like this:

Code:
#!/bin/bash

PLUGIN_NAME="Status"
PLUGIN_VERSION="1.0.0"
PLUGIN_BRIEF="Displays a dashboard of iTunes status."

function _cmd_status() {
    _show_current_track "Currently playing" 0
    _show_current_playlist "On playlist" 1
    local total_tracks=$(_tell_itunes "count tracks")
    local total_playlists=$(_tell_itunes "count playlists")
    echo "The iTunes library contains" \
        $(_pluralize "$total_tracks" "track") \
        "and" \
        $(_pluralize "$total_playlists" "playlist")
}

Browse Sam's Blog Subscribe to Sam's Blog

By day of June: 07, 08, 15.

By month of 2012: April, May, June, July, December.

By year: 2010, 2011, 2012, 2013.

Or by: category or series.

Comments

blog comments powered by Disqus
© 2009-2013 Sam Graham, unless otherwise noted. All rights reserved.