A New Script for Skipping Tracks

A while back I wrote a simple script for skipping tracks (and a couple of other things) for Rhythmbox.  Now that Ubuntu is moving to Banshee as their default media library application I have tossed together a new script for use with Banshee.

The trouble with Rhythmbox was getting the system to understand, when attached remotely, which monitor contained Rhythmbox.  This was dealt with by making use of the $DISPLAY variable.  Banshee makes this problem a bit more difficult.  Banshee uses dbus and dbus is more difficult to guess at and more difficult to inquire.  A little research has given me a workable bit of code that gets me there.  (I am still researching this code either for better or safer or more elegant solutions.)

I have built in some logic to make the script handle situations where the user inputs a command (argument) that is not necessarily appropriate to the current state of Banshee. It should handle most of what you might (accidentally?) throw at it. I still want to give it some parsing abilities so that when it displays the currently playing information it’s more user friendly. I’ll just add that here when I get that built.

I have built a code section (in two parts) for seeking (forward and reverse). The problem is that in my version of Ubuntu there is a dependency bug (in dbus) so the seeking won’t work for Banshee from the command line. I have included it here for folks for whom this bug does not apply. Feel free to comment on your operating system and Banshee version if my code works for you.

To get the seek code working simply paste the two parts into the two places in the script where I have placed markers. (You may optionally uncomment (remove the #’s) from the two lines in the help section near the end of the script, but it’s not required for the seek code to function. If you are running Ubuntu 10.04 like me you won’t need the seek code unless you have dealt with the dbus bug yourself.)

##
#!/bin/bash
# Banshee Control Script
# by JamesIsIn from JamesIsIn.com
# Do something nice today.

# First tell the system how to find the current running version of Banshee if you are running this script remotely.  If you only use the script locally you can comment out this export line.
# This command reports a host of permissions errors and doesn't need to display its output to the user so we divert STDERR to null.

export $(strings /proc/*/environ 2> /dev/null | grep DBUS_SESSION | tail -1)


# Now we can manipulate Banshee.
# Grab that variable...

argument=$1

## The first part of the seek code belongs here.



##



# ... and shake it!

   if [ "$argument" = "p" ]; then
      playbackstatus=`banshee --query-current-state`
      pbstat=${playbackstatus#* }
         if [ "$pbstat" = "paused" ]; then
            printme="I am resuming playback."
            banshact="banshee --play"
            banshow="banshee --query-title --query-artist --query-track-number --query-track-count --query-album --query-disc --query-year --query-duration"
         elif [ "$pbstat" = "idle" ]; then
            printme="I am beginning playback."
            banshact="banshee --play"
            banshow="banshee --query-title --query-artist --query-track-number --query-track-count --query-album --query-disc --query-year --query-duration"
         elif [ "$pbstat" = "playing" ]; then
            printme="I am pausing playback."
            banshact="banshee --pause"
         else
            printme="Is Banshee even on?  I'm confused." 
         fi

   elif [ "$argument" = "play" ]; then
      playbackstatus=`banshee --query-current-state`
      pbstat=${playbackstatus#* }
      if [ "$pbstat" = "idle" ]; then
         printme="I am beginning playback."
         banshact="banshee --play"
         banshow="banshee --query-title --query-artist --query-track-number --query-track-count --query-album --query-disc --query-year --query-duration"
      elif [ "$pbstat" = "paused" ]; then
         printme="I am resuming playback."
         banshact="banshee --play"
         banshow="banshee --query-title --query-artist --query-track-number --query-track-count --query-album --query-disc --query-year --query-duration"
      elif [ "$pbstat" = "playing" ]; then
         printme="Banshee is already playing."
      else
         printme="Is Banshee even on?  I'm confused."
      fi

   elif [ "$argument" = "pause" ]; then
      playbackstatus=`banshee --query-current-state`
      pbstat=${playbackstatus#* }
      if [ "$pbstat" = "playing" ]; then
         printme="I am pausing playback."
         banshact="banshee --pause"
      elif [ "$pbstat" = "paused" ]; then
         printme="Banshee is paused.  Use p or play to resume playback."
      elif [ "$pbstat" = "idle" ]; then
         printme="Banshee is stopped.  Use play to resume playback."
      else
         printme="Is Banshee even on?  I'm confused."
      fi

   elif [ "$argument" = "stop" ]; then
      playbackstatus=`banshee --query-current-state`
      pbstat=${playbackstatus#* }
      if [ "$pbstat" = "playing" ]; then
         printme="I am stopping playback."
         banshact="banshee --stop"
         
      elif [ "$pbstat" = "paused" ]; then
         printme="Banshee was paused and I have now stopped it."
         banshact="banshee --stop"
         
      elif [ "$pbstat" = "idle" ]; then
         printme="Banshee is already stopped."
      else
         printme="Is Banshee even on?  I'm confused."
      fi

   elif [ "$argument" = "n" ]; then
      playbackstatus=`banshee --query-current-state`
      pbstat=${playbackstatus#* }
      if [ "$pbstat" = "playing" ]; then
         printme="I am skipping to the next track."
         banshact="banshee --next"
         banshow="banshee --query-title --query-artist --query-track-number --query-track-count --query-album --query-disc --query-year --query-duration"
      elif [ "$pbstat" = "paused" ]; then
         printme="Banshee is paused.  Use p or play to resume playback."
      elif [ "$pbstat" = "idle" ]; then
         printme="Banshee is stopped.  Use play to resume playback."
      else
         printme="Is Banshee even on?  I'm confused."
      fi
   

   elif [ "$argument" = "r" ]; then
      printme="I am going to rewind now.  Doing this early enough will supposedly go to the previous track."
      banshact="banshee --previous"
      banshow="banshee --query-title --query-artist --query-track-number --query-track-count --query-album --query-disc --query-year --query-duration"
      
# I should be able to prettify this and account for null variables.
# what I want: You are listeing to song by so-and-so (x of y) from album [] [year] ti:me.

   elif [ "$argument" = "s" ]; then
      playbackstatus=`banshee --query-current-state`
      pbstat=${playbackstatus#* }
      if [ "$pbstat" = "playing" ]; then
         printme="This is what is currently playing:"
         banshow="banshee --query-title --query-artist --query-track-number --query-track-count --query-album --query-disc --query-year --query-duration"
      elif [ "$pbstat" = "paused" ]; then
         printme="Banshee is currently paused here:"
         banshow="banshee --query-title --query-artist --query-track-number --query-track-count --query-album --query-disc --query-year --query-duration"
      elif [ "$pbstat" = "idle" ]; then
         printme="Banshee is currently stopped.  Use play to resume playback."
      else
         printme="Is Banshee even on?  I'm confused."
      fi

## The second part of the seek code belongs here.



##

   elif [ "$argument" = "c" ]; then
      playbackstatus=`banshee --query-current-state`
      pbstat=${playbackstatus#* }
      printme="Banshee is currently $pbstat."

   else
      printf "\nI'm sorry.  I only understand the following arguments:\n\n"
      printf "  p     -- attempt to toggle between play and pause\n"
      printf "  r     -- rewind to beginning or skip reverse\n"
      printf "  n     -- skip to next track\n"
      printf "  s     -- show what's playing\n"
      printf "  play  -- play\n"
      printf "  pause -- pause\n"
      printf "  stop  -- stop\n"
      printf "  c     -- display the current state of Banshee\n\n"
# You may want to uncomment the next two lines if you are using the seek code.
#      printf "  ff    -- fast forward (include seconds as ff 10)"
#      printf "  rr    -- rewind (include seconds as rr 5)"
      printf "Note that the arguments do not use a hyphen.  Please try again.\n\n"
      exit
   fi


$banshact
echo
echo $printme
echo
$banshow
echo


exit

##

As you can see, I have given play/pause toggling (where banshee itself doesn’t really have it) through the clever use of an if-loop (I’ll just pat myself on the back, ok?). Also it tells you what is playing anytime you start playing something (new or resumed).

Point of interest, there is bit of code that was not working in the script:

banshee –play; banshee –query-title –query-artist –query-track-number –query-track-count –query-album –query-disc –query-year –query-duration

Thing is if you paste this into a terminal it works perfectly. The problem is that semi-colon. On the command line it’s just fine, but in the script there must be a space after the --play or the shell will interpret the argument as literally --play; and it won’t work.

So the basic usage of the script is in this format:

Bs p

I placed this script in /usr/local/bin on the hi-fi machine. I called it merely Bs. That way the script is available to all users on that machine and is easy to call up from the terminal.

Be sure to make the file executable:

sudo chmod a+x /usr/local/bin/Bs

For those who would like to add the seek functionality, here it is. You can always test it on your system to see if it works and remove it (or comment it out) if it doesn’t.

##
#!/bin/bash
# Seek functionality for Banshee Control Script
# by JamesIsIn from JamesIsIn.com
# Do something nice today.

## This is the first part of the seek code.

seekseconds=$2
roundseek=$( printf "%0.f\n" $seekseconds )

##


## This is the second part of the seek code.

   elif [ "$argument" = "ff" ]; then
      playbackstatus=`banshee --query-current-state`
      pbstat=${playbackstatus#* }
         if [[ $roundseek =~ ^[0-9]+$ ]]; then
            currentlocation=`banshee --query-position`
            currloc=${currentlocation#* }
            roundloc=$( printf "%0.f\n" $currloc )
            seekchange=$(( roundloc + roundseek ))
               if [ "$pbstat" = "playing" ]; then
                  printme="I am advancing playback by $roundseek seconds."
                  banshact="banshee --set-position=$seekchange"
                  banshow=""
               elif [ "$pbstat" = "paused" ]; then
                  printme="Banshee is paused but I have advanced the pause location by $roundseek seconds."
                  banshact="banshee --set-position=$seekchange"
                  banshow=""
               elif [ "$pbstat" = "idle" ]; then
                  printme="Banshee is neither playing nor paused and thus I am not able to advance anything"
                  banshact=""
                  banshow=""
               else
                  printme="Is Banshee even on?  I'm confused."
                  banshact=""
                  banshow=""
               fi
         else
            printme="When using ff you must enter seconds in the format \"Bs ff 5\" in order for me to process your request."
            banshact=""
            banshow=""
         fi   
      
   elif [ "$argument" = "rr" ]; then
      playbackstatus=`banshee --query-current-state`
      pbstat=${playbackstatus#* }
         if [[ $roundseek =~ ^[0-9]+$ ]]; then
            currentlocation=`banshee --query-position`
            currloc=${currentlocation#* }
            roundloc=$( printf "%0.f\n" $currloc )
            seekchange=$(( roundloc - roundseek ))
               if [ "$pbstat" = "playing" ]; then
                  printme="I am rewinding playback by $roundseek seconds."
                  banshact="banshee --set-position=$seekchange"
                  banshow=""
               elif [ "$pbstat" = "paused" ]; then
                  printme="Banshee is paused but I have rewound the pause location by $roundseek seconds."
                  banshact="banshee --set-position=$seekchange"
                  banshow=""
               elif [ "$pbstat" = "idle" ]; then
                  printme="Banshee is neither playing nor paused and thus I am not able to rewind anything"
                  banshact=""
                  banshow=""
               else
                  printme="Is Banshee even on?  I'm confused."
                  banshact=""
                  banshow=""
               fi
         else
            printme="When using rr you must enter whole-numbered seconds in the format \"Bs rr 5\" in order for me to process your request."
            banshact=""
            banshow=""
         fi



##

Have fun with this one too. Suggestions are welcome.

Share

7 thoughts on “A New Script for Skipping Tracks

  1. Apparently though it is not listed in the banshee man page, there is a –toggle-playing argument available (tested and works in 1.6.1). So I can replace my clever play/pause toggle section with one elif statement using –toggle-playing. So much for my clever coding. (I probably won’t though since I get more functionality out of my code than I could using just the –toggle-playing argument.)

  2. Nice one.
    What’s the “2> /dev/null ” part supposed to represent? It looks like redirection of errors but I can’t figure it out since running the whole command stops at the error ” is not a file”. If it’s what you wanted to stop the run, it feels dirty. If not I have no idea what it is.

    Btw I’ve had this problem since day one : Banshee doesn’t provide a command line to launch a smart playlist. And in windows media player 11 I could launch it because it was represented as a file but I don’t find anything resembling a smart playlist file in the banshee directories I looked in (not thoroughly though).

    If you want to comment on my first question or the second, you can email me. Thnaks for the export line anyway, it was vital :D

    1. Wait, seeing from my own comment that 2 & g t is just 2>, I guess 2 means STDERR and /dev/null is some file used to throw stuff away.
      I still don’t see why it should stop and what the DBUSSESISON is…

      1. Yep, a null-file is just a void where you can throw things you don’t ever care to care about caring.

        You understand the re-direction correctly. Sorry that sometimes that code gets muddled by the code parser.

  3. You’re my hero! I’ve been looking for this line:

    export $(strings /proc/*/environ 2> /dev/null | grep DBUS_SESSION | tail -1)

    all over the internet.

Leave a Reply

Your email address will not be published. Required fields are marked *