Friday, June 3, 2011

Controlling mpd with notifications for Gnome 3 and KDE

If you're using media player daemon, this script might be useful for you. It can start the daemon, controll the playback, delete actual playing song and create notifications of the player state with gdbus.


gdbus is used in Gnome, but it also works with KDE.
Script is using mpc (media player client) to control the playback.

It supports:
- parameter play starts the mpd daemon, if the daemon was already started then toggles playback
- parameter stop stops the playback, kill the daemon
- parameter next and prev skip to the next and previous song
- parameter current returns 0 when actual song exists or 1 if the song was removed
- parameter del remove actual playing song, you can use del y for skipping any prompts for confirmation
- parameter help diplays script options
- notifications are shown when the song has change or when the mpd state has changed (using play and stop parameters) and when the playing song was removed.

Here's the script:

#!/bin/bash

if [ $# -eq 0 ];then
  echo Invalid count of parameters, type \'$0 help\' for help.;
  exit 1;
fi

MPCCMD="mpc"
MUSICDIR=~/music
ICONDIR=~/.icons/

#display notification (parameters: $1=appname; $2=summary; $3=body; $4=icon)
dbusnotify(){

 stat=`$MPCCMD | sed -n '2p' | cut -d " " -f 1`
 title=`$MPCCMD | head -n 1`
 
 #store actual song number for song change notification
    $MPCCMD | sed -n '2p' | cut -d "#" -f 2 | cut -d "/" -f 1 > /tmp/mpdsong

 case "$1" in
  "play" ) if [ "$stat" == "[playing]" ]; then icon=player_play; else icon=player_pause; fi ;;
  "stop" ) icon=player_stop; stat="[stopped]" ;;
  "prev" ) icon=player_start ;;
  "next" ) icon=player_end ;;
  "current" ) icon=reload ;;
  "del" ) icon=remove; stat="[removed]" ;;
  * ) icon=messagebox_warning; stat=$MPCCMDctrl; title="Unknown operation";;
 esac

 notify-send "$stat" \ "$title" -t 5000 -i $icon

###
# uncomment following lines to enable notification via dbus, don't forget to comment previous line 'notify-send'
###
# msgid=`gdbus call --session --dest org.freedesktop.Notifications --object-path /org/freedesktop/Notifications --method org.freedesktop.Notifications.Notify "mpc" 42 "$ICONDIR$icon" "$stat" "$title" [] {} 3000 | cut -d " " -f 2 | cut -d "," -f 1`

###
# no need to kill in KDE4
###
# #kill previous msg
# let prevmsgid=$msgid-1
#
# gdbus call --session --dest org.freedesktop.Notifications --object-path /org/freedesktop/Notifications --method org.freedesktop.Notifications.CloseNotification $prevmsgid > /dev/null
#
# #time to wait before closing notification
# (sleep 3
# gdbus call --session --dest org.freedesktop.Notifications --object-path /org/freedesktop/Notifications --method org.freedesktop.Notifications.CloseNotification $msgid > /dev/null) &
}

#enabling notifications (0|1)
notifications=1

case "$1" in
 "play" ) 
   #if mpd is not started, 0 is returned
   run=$($MPCCMD stats | grep -c "")

   #if mpd is not started, start it and play music
   #else toggle play/pause
   if [ "$run" == "0" ];then
    mpd ~/.mpd/mpd.conf; sleep 1;
    $MPCCMD play;
    if [ $notifications -eq 1 ]; then
     dbusnotify play
    fi
   else
    $MPCCMD toggle
    if [ $notifications -eq 1 ]; then 
     dbusnotify play
    fi
   fi
 ;;

 "stop" )  
   #if mpc is in state 'stopped', 1 is returned, otherwise some greater number is returned
   stopped=$($MPCCMD | grep -c "")
   stopplaying="$MPCCMD stop"

   if [ "$stopped" == "1" ];then
    mpd --kill;
   else
    $MPCCMD stop;
    if [ $notifications -eq 1 ]; then
     dbusnotify stop
    fi
   fi
 ;;

 "next" ) 
   #stopped=$($MPCCMD | grep -c "")
   #if [ "$stopped" != "0" ];then
   $MPCCMD next;
   if [ $notifications -eq 1 ]; then
    dbusnotify next
   fi
 ;;
 
 "prev" ) 
   #stopped=$($MPCCMD | grep -c "")
   #if [ "$stopped" != "0" ];then
   $MPCCMD prev;
   if [ $notifications -eq 1 ]; then
    dbusnotify prev
   fi
 ;;

 "current" ) 
   #path to currently playing song
   pathtofile=$($MPCCMD --format "%file%" | head -n 1)

   #move to Music DIR, because pathtofile works from here
   cd $MUSICDIR;
   exists=$(ls "$pathtofile" 2>/dev/null)
     
   #if $MPCCMD is stopped, 1 is returned
   stopped=$($MPCCMD | grep -c "")

   if [ "$pathtofile" != "$exists" ] && [ "$stopped" != "1" ];then
    #number 1 is indicating that current playing song is removed (does not exist)
    echo 1;
   else echo 0;
   fi

   #notify if song has changed
   #song number in file
   songnr=`cat /tmp/mpdsong 2>/dev/null`
   #actual song number
   actual=`$MPCCMD | sed -n '2p' | cut -d "#" -f 2 | cut -d "/" -f 1`
     
   if [ ! -f /tmp/mpdsong ] || [ "$songnr" != "$actual" ]; then
      dbusnotify current
   fi
 ;;

 "del" )  
   #store current song name
   current=$($MPCCMD current)
   #path to current song
   pathtofile=$($MPCCMD --format "%file%" | head -n 1)
 
   cd $MUSICDIR;
 
   #if 'del y' was given at the cmd line, delete file without any question
   if [ "$2" == 'y' ]; then
    echo "File removed.";
    if [ $notifications -eq 1 ]; then
     dbusnotify del
    fi
    exec rm "$pathtofile";
   fi
   echo ""
 
   #ask for confirmation
   echo  "Type 'y' if you want to remove this file > " $current;
   read del;
 
   if [ 'y' == "$del" ]; then
    echo "File removed.";
    exec rm "$pathtofile";
   else
    echo File not removed.;
   fi
 ;;

 "help" ) 
   echo ""
   echo "KrisKo 2010" 
   echo ""
   echo "Usage: mpcctrl [OPTION]"
   echo ""
   echo "Script accepts following options:"
   echo "play  start mpd and toggle between play/pause"
   echo "stop  stop mpd playback and end mpd"
   echo "next  play next song"
   echo "prev  play previous song"
   echo "current  display if current song is removed"
   echo "del  delete current song"
   echo "del y  delete current song without prompt"
   echo "help  display this help"
   echo ""
 ;;

 * ) 
   echo "Unrecognized parameter. Type '$0 help' for help"
 ;;
esac

exit 0



______________________________________________________________________________________
I use this script with conky which displays playback information...


Here's my conkyrc:
______________________________________________________________________________________
#define variables
 template0 0
 template1 1

TEXT
 $if_mpd_playing${color blue}${mpd_status} ${color white}${mpd_elapsed}/${mpd_length} ${color blue}Volume:${color white}${mpd_vol}% ${color blue}Shuffle:${color white}${mpd_random} ${color blue}Random:${color white}${mpd_repeat} ${color blue}Bitrate:${color white}${mpd_bitrate}kbps
 ${color blue}${mpd_bar 3 450}
 ${color white}${if_match ${template1} == ${exec mpcctrl current}}${color red}${endif}${mpd_smart}${endif}

2 comments:

  1. I'm getting
    "
    sleep: invalid option -- '-'
    Try `sleep --help' for more information.
    "
    I guess its because of line 29.

    ReplyDelete
  2. Hi, yes there is an error an the line 29.
    the gdbus should be on a new line:
    (sleep 3
    gdbus call...
    or you can put ';' behind sleep:
    sleep 3; gdbus...

    ReplyDelete