basileaf /bin/mpd-on-change

#!/bin/bash
# 
# ~/bin/mpd-on-change - Waits for MPD's status to change (usually the end of a
#                       song), and optionally executes an action afterwards.

# Print a help message
function usage {
    echo "
mpd-on-change  -  Waits for MPD's status to change (usually the end of a song),
                  and optionally executes an action afterwards.

Usage: mpd-on-change [[-i | --interval] seconds] [[-n | --songs] songs] \\
                     [[-a | --action] command.. ]

Options:
  -a, --action    Execute some action after song(s) finish. Anything after this
                  option is taken to be a command.
  -i, --interval  Set the time between checking the current song. May be in any
                  format supported by sleep. Default is 2.
  -n, --songs     Set the number of songs to wait for. Default is 1.
  -h, --help      Display this help message.

Note  that stopping a song, or starting one when MPD is stopped,  will signal a
change as if the song had finished.
"
}

# What to do in case of incorrect usage
function error_exit {
    usage
    exit 1
}

# $number is the number of songs to complete before finishing up
# $interval is the length of time between checking the current song
# $action is what is executed after the songs play

number=1
interval=2
action=:

# Detect command line arguments
while [ "$1" != "" ]; do
    case $1 in
        -a | --action )     shift
                            action=$*
                            break
                            ;;
        -i | --interval )   shift
                            interval=$1
                            ;;
        -n | --songs )      shift
                            number=$1
                            ;;
        -h | --help )       usage
                            exit
                            ;;
        * )                 error_exit
    esac
    shift
done

# Tests that $number is a non-negative integer
test $number -ge -1 2> /dev/null || error_exit

# Tests to see if $interval is valid input for sleep
# Note that this adds an extra sleep command, which usually won't matter
sleep $interval 2> /dev/null || error_exit


# $song keeps track of which song needs to finish
# $cur_song is the currently playing song

song=`mpc | head -n 1`
cur_song=$song

# $count keeps track of how many songs have finished playing
# This is the meat of the program, which periodically checks the current song
count=0
until [ $count -ge $number ]; do
    while [ "$cur_song" = "$song" ]; do
        sleep $interval
        cur_song=`mpc | head -n 1`
    done
    count=$((count + 1))
    song=`mpc | head -n 1`
done

# Action to be executed at the end, default does nothing
$action