public
Last active

Linux Spotify Ad Mute

  • Download Gist
spotify-admute.sh
Shell
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
#!/bin/bash
 
#Linux Spotify Ad Mute v2
#Put this script in the directory the "spotify" binary is in (e.g. /usr/share/spotify).
#To open Spotify, run it instead of the "spotify" binary.
#System sound will be muted as soon as an ad plays
#Find updated versions at: http://pcworldsoftware.kilu.net/files/link_spotify-admute.php and/or https://gist.github.com/pcworld
#On Debian, you need the package "pulseaudio-utils" for the command line util "pactl" which used in this script
#
#Update: For newer 0.8.x versions (x>4; such as 0.8.8), use this script: https://gist.github.com/pcworld/3198763/#comment-813440
#For 0.9.x: https://gist.github.com/pcworld/3198763/#comment-857143
#
#Copyright (c) 2012, "pcworld", 0188801@gmail.com
#All rights reserved.
#
#Redistribution and use in source and binary forms, with or without
#modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the author nor the
# names of its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
#
#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
#ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
#WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
#DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
#DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
#(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
#ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
#(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
#SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # http://stackoverflow.com/a/246128
 
dbus-monitor "type='signal',path='/org/mpris/MediaPlayer2',member='PropertiesChanged'" | grep --line-buffered 'string "Metadata"' |
while read -r line ; do
if ! [[ "`dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify / org.freedesktop.MediaPlayer2.GetMetadata`" == *'string "mpris:artUrl"'* ]]
then
pactl set-sink-mute 0 yes
else
pactl set-sink-mute 0 no
fi
done &
$DIR/spotify "$@" &
wait $! &&
test -z "`jobs -p`" || kill `jobs -p` # http://stackoverflow.com/a/2618497

Thank you so much for this script!

replace the current while loop with the following to mute just spotify. not every application

while read -r line ; do
    num=$(pactl list | grep -E '(^Sink Input)|(media.name = \"Spotify\"$)' | awk '/Spotify/ {print a} {a = $0}' | cut -c 13-)
    if ! [[ "\`dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify / org.freedesktop.MediaPlayer2.GetMetadata\`" == \*'string "mpris:artUrl"'\* ]]
    then
        pactl set-sink-input-mute $num yes
    else
        pactl set-sink-input-mute $num no
    fi
done &

hey, just made an account to say thanks! great script and thanks bim9262 as well. everything works perfectly. if you are new to linux like me you may find you are not able to move the file into the spotify folder because you do not have permission. you can move it with terminal. type:

sudo mv (the directory of the file)/spotify-admute.sh usr/share/spotify

i would like to learn how to add to the script so that it plays music from the default music player when spotify is silent. can anyone point me into the right direction.

thanks again!

Assuming you are using the Ubuntu distribution, the default player is rhythmbox-client. In the If statement add a command to play then stop music from rhythmbox, for the manual page of rhythmbox use the command: man rhythmbox-client

Similar to bim9262, I spent a long time messing around with pactl to get the same desired effect (muting only Spotify not any other application). I ended up using the script at: http://askubuntu.com/questions/180612/script-to-mute-an-application
Also on a side note I've been able to use icecast to stream the music to my mobile devices

Just add a line to start the song after the mute

then
pactl set-sink-input-mute $num yes
rhythmbox URL
else
pkill rhythmbox
pactl set-sink-input-mute $num no
fi

Will play an internet radio during the mute and kill it after its over

while read -r line ; do
    num=$(LANG=C pactl list | grep -E '(^Sink Input)|(media.name = \"Spotify\"$)' | awk '/Spotify/ {print a} {a = $0}' | cut -c 13-)
    if ! [[ "`dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify / org.freedesktop.MediaPlayer2.GetMetadata`" == *'string "mpris:artUrl"'* ]]
    then
        pactl set-sink-input-mute $num yes
    else
        pactl set-sink-input-mute $num no
    fi
done

Hi all. This script worked superb for a long while up until I updated to spotify 0.8.8 from 0.8.4. I believe it had difficulty muting/unmuting with the new version.

This is what I use now:

while read -r line ; do
    num=$(LANG=C pactl list | grep -E '(^Sink Input)|(media.name = \"Spotify\"$)' | awk '/Spotify/ {print a} {a = $0}' | cut -c 13-)
    string="`dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify / org.freedesktop.MediaPlayer2.GetMetadata`"
    if [[ $string != *"mpris:artUrl"* && $string == *"mpris:length"* ]]
        then
            pactl set-sink-input-mute $num yes
        else
            pactl set-sink-input-mute $num no
        fi
done &

Could you post an ls -al of your spotify-client folder?
The script worked fine for me as well, but I had to reinstall everything after crashing my entire system and the current version installs everything to /opt/spotify/..., not anymore to /usr/share/spotify. So now root owns everything, instead of "user". As far as I remember, it was "user" with the older client version...
Dunno what is the exact problem, but if I put the admute-Script into the /opt/... directory and start it there, my whole graphical environment crashes.

high chunged,
did you put the new spotify_block_ads.sh in /usr/bin or in the old /usr/share/spotify/ ?
does it work for you ?
if yes, what is the exactly content of /usr/share/spotify/spotify_block_ads.sh now ?
I have the same problem, muting doesn't work anymore ? I tried with your content.
Thanks in advance !

chunged, are you sure that it is working with the latest Spotify? I've tried your code but it doesn't mute anymore.

In ubuntu 12.10 I put it on /usr/bin, but doesn't work.

There's this error on terminal output:

ChannelError(0, 1, social_get_popularity)

Just FYI, I use an old version of Spotify (as I thought the risk of an update breaking this script was too high), that's a reason why I haven't updated this script yet.

(Note: I've added syntax highlighting to some comments, because GitHub otherwise breaks its contents (e.g. the asterisks).)

Just signed up to say it now works since the above changes :D

Using Spotify version 0.8.8.323

Sorry for my ignorance, but I have no idea of how to run this script. I downloaded it, changed it according to AwsomePlunger and moved it to /opt/spotify/spotify-client since I run Ubuntu 13.04 and Spotify client 0.8.8. But how do I run the script? If I double-click the 'spotify-admute.sh' file I just get a file-editor (gedit). Then I tried 'spotify spotify-admute.sh' in a terminal, but this only runs spotify and not the script.

Thank you for your help

@smadsen100:
First, make the script executable. Either run in terminal:
chmod +x /opt/spotify/spotify-client/spotify-admute.sh (if that's the correct path; the folder must contain the "spotify" binary)
or right-click the file in Nautilus (Ubuntu's default file manager) -> Properties -> Permissions -> Check "Allow executing file as program".
Then, double-clicking it in Nautilus might work.
You can also add a new "launcher" to your desktop environment's application menu, point it to "/opt/spotify/spotify-client/spotify-admute.sh", or, if that doesn't work, set "sh /opt/spotify/spotify-client/spotify-admute.sh" as the command.

Let me know if something wasn't clear or you're having problems.

anyone can upload the old version of spotify 1:0.8.8.323.gd143501.250-1 ? unfortunately i've upgrade to 0.9 deleting the old one... :(

spotify-client_0.8.4.103.g9cb177b.260-1_i386.deb (created with dpkg-repack): http://www.load.to/5a1dFYD8Fo/spotify-client_0.8.4.103.g9cb177b.260-1_i386.deb (sha256sum: 9334f5e23e2cd2cfbac147c122a0f009d348af9a3743ba274104b0e9cf743c48)

@AwsomePlunger:
Thanks for pointing that out. I personally won't work on updating this script for new versions in the near future, I haven't read good things at all about recent Spotify updates on their forums.
But if anyone updates the script, please post it (or a reference to it) here!
The song length is in µs (1µs=10⁻⁶s), so multiply by 10⁶ (or cut off the trailing zeros) and you have the song length in seconds.

Spotify 0.8.4 crashes for me since today. :( Hope this is only temporary. Am I the only one?

Edit 2013-05-17 12:48 UTC: Works again.

I have the same issue it crashes on startup deleting the cache and config folders also didn't help. Hopefully it really is only temporary!

@honigdachs Works again for me :)

Doesn't work with version 0.9.0.133 it looks like this version doesn't update DBUS during the ads.

@donrudo: See [1] and [2].
If you don't want to update this script, you can e.g. downgrade to Spotify 0.8.4.

I wrote a script that works with the latest version using bits and pieces of code above. Here's the code:

#!/bin/bash

was_paused=0 # if last state was paused
ad=0 # if an ad is probably playing right now

while true; do
    num=$(pactl list | grep -E '(^Sink Input)|(media.name = \"Spotify\"$)' | awk '/Spotify/ {print a} {a = $0}' | cut -c 13-)

    icon_name=$(xprop -name 'Spotify - Linux Preview' _NET_WM_ICON_NAME | cut -d \" -f 2)
    song_name=$(dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify / org.freedesktop.MediaPlayer2.GetMetadata | grep xesam:title -A 1 | grep variant | cut -d \" -f 2)

    if [[ "$song_name" && "$icon_name" =~ "$song_name" ]]; then
        if [ "$was_paused" -eq 0 -a "$ad" -ne 0 ]; then
            # wait 1 second after a commercial
            sleep 1
        fi

        ad=0
        pactl set-sink-input-mute $num no
    else
        ad=1
        pactl set-sink-input-mute $num yes
    fi

    if [ "$icon_name" = "Spotify" ]; then
        was_paused=1
    else
        was_paused=0
    fi

    sleep 0.5
done

Here's how it works: spotify window has a property _NET_WM_ICON_NAME, which does get updated with the name of the ad in the latest version (0.9.1.55). DBUS, however, is not updated and stays the same after the song. That means an ad is played right now if the title of the track reported by DBUS is different from the window property. I also added 1 second delay after the ad because of latency issues.

This also means that this script is probably not compatible with previous versions, but don't quote me on this.

Update: I'm releasing my code into the public domain. The parts of this script that I haven't written myself are covered by other licenses.

@OlegSmelov That's great! Added a link to my scipt's header comment.
Have you considered releasing your script under an open source license?

@pcworld Yeah, sure! I've updated my comment. My code is in the public domain now.

hi, i am running ubuntu 13.04 with spotify 09.05
i tried to use the script of OlegSmelov but failed. the sound mutes after each song!
the ads are not blocked, and when they appear the sound doesn't mute!
any ideas?
thanks

@heisamann I modified the script and it's working for me. Give it a shot!

#!/bin/bash
# Updated from https://gist.github.com/pcworld/3198763/#comment-857143

was_paused=0 # if last state was paused
ad=0 # if an ad is probably playing right now

while true; do
    num=$(pactl list | grep -E '(^Sink Input)|(media.name = \"Spotify\"$)' | awk '/Spotify/ {print a} {a = $0}' | cut -c 13-)
    #icon_name=$(xprop -name 'Spotify - Linux Preview' _NET_WM_ICON_NAME | cut -d \" -f 2)
    icon_name=$(xprop -name 'Spotify - Linux Preview' WM_ICON_NAME | awk -F"– " '{print $2}' | cut -d \" -f 1)
    song_name=$(dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify / org.freedesktop.MediaPlayer2.GetMetadata | grep xesam:title -A 1 | grep variant | cut -d \" -f 2)

    if [[ "$song_name" && "$icon_name" =~ "$song_name" ]]; then
        if [ "$was_paused" -eq 0 -a "$ad" -ne 0 ]; then
            # wait 1 second after a commercial
            sleep 1
        fi

        ad=0
        pactl set-sink-input-mute $num no
    else
        ad=1
        pactl set-sink-input-mute $num yes
    fi

    #if [ "$icon_name" = "Spotify" ]; then
    if [ -z "$icon_name" ]; then
        was_paused=1
    else
        was_paused=0
    fi

    sleep 0.5
done

thanks halfwise77!
i copied your script in spotify folder under the name spotify-admute.sh, and made it excutable.
i tried spotify from the terminal, and found out that the sound doesn't mute after each song :)
but, ads does not get muted as well :(
so the script did not function to me.
what confuses me is that i don't see any mentioning of spotify-admute.sh in terminal when i execute spotify.
thanks again

@heisamann: You have to execute @halfwise77's script manually after starting Spotify.

thanks pcworld, i started spotify, then i excuted halfwise77 script spotify-admute.sh from the terminal. i received this message from terminal:
spotify-admute.sh: 13: spotify-admute.sh: [[: not found

and spotify is completely muted.

@heisamann: Are you sure the script is running in bash? Try to run it explicitly via bash -c ./spotify-admute.sh.

wow, it worked out using the previous hint of @pcworld.
but i am sure that i am using bash shell. i tried executing spotify-admute.sh before by using:
sh spotify-admute.sh
does it make a difference?
thanks a lot

... and thanks a lot to @halfwise77 and @pcworld

i tried executing spotify-admute.sh before by using:
sh spotify-admute.sh
does it make a difference?

$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Jul 28  2011 /bin/sh -> bash

Maybe your /bin/sh is linked to something else.
If your terminal runs bash, you should also be able to run the script via ./spotify-admute.sh.

Or add the following to your spotify-admute.sh (as seen in my original script), then you will only have to run that script to start Spotify, and the "ad muter" script will shutdown as soon as Spotify exits:

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # http://stackoverflow.com/a/246128
$DIR/spotify "$@" &
wait $! &&
test -z "`jobs -p`" || kill `jobs -p` # http://stackoverflow.com/a/2618497

Edit: Put my first line (DIR=…) before @halfwise77's script and change his done to done &, then add my other three remaining lines.

you are right, in my case it is linked to dash not bash:
$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Mar 12 17:35 /bin/sh -> dash

Spotify 0.8.4 doesn't output any sound when playing, first experienced yesterday (independent of this admute-script). :(

tried to use @halfwise77's updated script in combination with @pcworld addon
now i this error message repeatingly in terminal:
"You have to specify a sink input index and a mute boolean"
any advise on it?

@darknils:
Do you use PulseAudio on your system? Try replacing pactl set-sink-input-mute $num no with pactl set-sink-mute 0 no (same with the "yes" line), however this will mute the whole system volume, and not just Spotify while an ad plays.

yes using PulseAudio.
now i don't get the error message but it won't mute either.

also noticed an other error message direct at the start
/opt/spotify/spotify-client/spotify-admute.sh: Line 37: $'\r': command not found

using:
ubuntu 12.04 LTS
spotify 0.9.1.55.gbdd3b79f

these lines are in the spotify-admute.sh

#!/bin/bash
# Updated from https://gist.github.com/pcworld/3198763/#comment-857143

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # http://stackoverflow.com/a/246128

was_paused=0 # if last state was paused
ad=0 # if an ad is probably playing right now

while true; do
    num=$(pactl list | grep -E '(^Sink Input)|(media.name = \"Spotify\"$)' | awk '/Spotify/ {print a} {a = $0}' | cut -c 13-)
    #icon_name=$(xprop -name 'Spotify - Linux Preview' _NET_WM_ICON_NAME | cut -d \" -f 2)
    icon_name=$(xprop -name 'Spotify - Linux Preview' WM_ICON_NAME | awk -F"– " '{print $2}' | cut -d \" -f 1)
    song_name=$(dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify / org.freedesktop.MediaPlayer2.GetMetadata | grep xesam:title -A 1 | grep variant | cut -d \" -f 2)

    if [[ "$song_name" && "$icon_name" =~ "$song_name" ]]; then
        if [ "$was_paused" -eq 0 -a "$ad" -ne 0 ]; then
            # wait 1 second after a commercial
            sleep 1
        fi

        ad=0
        pactl set-sink-mute 0 no
    else
        ad=1
        pactl set-sink-mute 0 yes
    fi

    #if [ "$icon_name" = "Spotify" ]; then
    if [ -z "$icon_name" ]; then
        was_paused=1
    else
        was_paused=0
    fi

    sleep 0.5
done &

$DIR/spotify "$@" &
wait $! &&
test -z "`jobs -p`" || kill `jobs -p` # http://stackoverflow.com/a/2618497

@darknils
In case you don't use an english locale, extracting $num (which is the pulse-audio id of the spotify sink to mute) might fail, which is why pactl complains about the missing sink.

In my case (german locale) the output of pactl list looks like this:

Sink-Eingabe #13
[...]
Eigenschaften:
                media.role = "music"
                media.name = "Spotify"
                application.name = "Spotify"

With english locale however it looks like this:

Sink Input #13
[...]
        Properties:
                media.role = "music"
                media.name = "Spotify"
                application.name = "Spotify"

In order to use an english locale for pactl only, you can insert "LC_ALL=C" in front of the pactl call:

#Uses english locale, works independent from system locale.
num=$(LC_ALL=C pactl list | grep -E '(^Sink Input)|(media.name = \"Spotify\"$)' | awk '/Spotify/ {print a} {a = $0}' | cut -c 13-)

You could of course also modify the script to extract the sink id from the german text, but the above will work in other countries, too.

#German locale only:
num=$(pactl list | grep -E '(^Sink-Eingabe)|(media.name = \"Spotify\"$)' | awk '/Spotify/ {print a} {a = $0}' | cut -c 15-

using german version.
error message now: "Fehlgeschlagen: Entität nicht vorhanden"
and dosn't mute when add is runing

switched to international code line
but still same error message in console

I tried @OlegSmelov's script and it works fine for me. @halfwise's modification didn't.
For users with a non-English locale, I suggest to put export LANG= at the beginning of the script (after #!/bin/bash).

Forked halfwise77´s script. This works flawlessly for me.
Oh and mine shouts the title and artist to icecast2 audio broadcaster.
Original script: https://gist.github.com/pcworld/3198763/#comment-873221

Works flawlessly with current spotify-linux.
$ dpkg --list | grep spot
ii spotify-client 1:0.9.1.55.gbdd3b79.203-1 amd64 Spotify desktop client

$ lsb_release -a
Distributor ID: Ubuntu
Description: Ubuntu 12.10
Release: 12.10
Codename: quantal

Instructions on how to make a audio stream server:
http://askubuntu.com/questions/28496/how-do-i-setup-an-icecast-server-for-broadcasting-audio-in-my-network

#!/bin/bash
# Updated from https://gist.github.com/pcworld/3198763/#comment-873221
was_paused=0 # if last state was paused
ad=0 # if an ad is probably playing right now
oldSong=""

IceUser="<IceCast Admin>"
IcePass="<IceCast Password>"
IceMount="%2Fmystream.mp3"
BaseURL="http://localhost:8000/admin/metadata?mount=$IceMount&mode=updinfo&song="

while true; do
    num=$(pactl list | grep -E '(^Sink Input)|(media.name = \"Spotify\"$)' | awk '/Spotify/ {print a} {a = $0}' | cut -c 13-)
    #icon_name=$(xprop -name 'Spotify - Linux Preview' _NET_WM_ICON_NAME | cut -d \" -f 2)
    icon_name=$(xprop -name 'Spotify - Linux Preview' WM_ICON_NAME | awk -F"– " '{print $2}' | cut -d \" -f 1)
         META=$(dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify / org.freedesktop.MediaPlayer2.GetMetadata)
      song_name=$(echo -n "$META" | grep xesam:title -A 1 | grep variant | cut -d \" -f 2)
    song_artist=$(echo -n "$META" | grep xesam:artist -A 2 | grep string | grep -v xesam | cut -d \" -f 2)
    if [[ "$song_name" && "$icon_name" =~ "$song_name" ]]; then
        if [ "$was_paused" -eq 0 -a "$ad" -ne 0 ]; then
            # wait 1 second after a commercial
            sleep 1
        fi

        ad=0
        pactl set-sink-input-mute $num no
    else
        ad=1
        pactl set-sink-input-mute $num yes
        song_artist="Spotify"
        song_name="Advert"
    fi

    #if [ "$icon_name" = "Spotify" ]; then
    if [ -z "$icon_name" ]; then
        was_paused=1
    else
        was_paused=0
    fi

    if [[ "$song_name" != "$oldSong" ]]; then
      ## ! Uncomment these after you have a working IceCast stream ! ##
      #Song=$(echo -n "$song_artist - $song_name" | perl -pe's/([^-_.~A-Za-z0-9])/sprintf("%%%02X", ord($1))/seg');
      #echo "$song_artist - $song_name"
      #echo "----> Result:"
      #wget -O - --tries=1 --user=$IceUser --password=$IcePass --auth-no-challenge -q $BaseURL$Song
      #echo "-----------------------------------------------"
      oldSong="$song_name"
    fi
    sleep 0.5
done

I created an executable file based off of the instructions for 13.04 ubuntu, and saved the file in the spotify-client folder. I copied and pasted the suggested block of code which would play a song from rhythmbox during an ad.

I'm running spotify 9.something, the latest from their website at this time. It worked once, and muted for one ad.

Ever since spotify cannot play anything, and rhythmbox produces no sound either. I have uninstalled and reinstalled both spotify and rhythmbox, using synaptic, to no effect. I have deleted the script, to no effect. The script must have changed something deep in the sound settings, permanently. Where should I find these files, and how should I fix them?

I am THIS close to reinstalling my entire OS. this sucks.

EDIT: FIxed my problems using spotify and rhythmbox, but gave up on the ad mute for now.

I'm using Spotify 0.9.4, OlegSmelov's script, Linux Mint 15 x64. Any tips?

Error org.freedesktop.DBus.Error.ServiceUnknown: The name org.mpris.MediaPlayer2.spotify was not provided by any .service files
You have to specify a sink input index and a mute boolean

You have to run spotify first @skamlic

Did anyone tried it on kubuntu?

+Skamlic, you should do this to disable the changes:

pactl set-sink-mute 0 no

Cheers,

He everyone!
I can report, that OlegSmelovs Script works like a charm on my Opensuse Box:
Opensuse x86_64 13.1
Spotify Version: 0.9.1.183

(Just for information for not so mature linux users: Replace the spotify command in your spotify start button with the following command and everytime spotify starts the spotify-admute script will also start:

(spotify &); sh spotify-admute.sh

Lovely. Thank you all very much.
I tried the first file provided here, with the modification to mute only the spotify and it works on my fedora 18 (fc18.x86_64)
Spotify 0.9.1.55

Working on Ubuntu 12.10 with Spotify 0.9.4.183.
Using OlegSmelov's script with LC_ALL=C inside the $num definition, since i'm using a spanish locale.
Thank you all!

Somewhat of a update to my blocker, https://gist.github.com/pcworld/3198763/#comment-898010

Works like a charm, with muting and updates icecast with song information - even the special characters are done correctly.

Instructions on how to make a audio stream server:
http://askubuntu.com/questions/28496/how-do-i-setup-an-icecast-server-for-broadcasting-audio-in-my-network

Skamlic https://gist.github.com/pcworld/3198763/#comment-955964
-- This script fixes that problem by retrying the audio channel id getting until we get a valid one.

$ dpkg --list | grep spoti
ii spotify-client 1:0.9.4.183.g644e24e.428-1 amd64 Spotify desktop client

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 13.10
Release: 13.10
Codename: saucy

#!/bin/bash
## Config ##
IceUser="<ICECast Username>"
IcePass="<ICECast Password>"
IceMount="%2Fmystream.mp3" # = /mystream.mp3, the icecast mountpoint to modify
BaseURL="http://localhost:8000/admin/metadata?mount=$IceMount&mode=updinfo&song="
##/Config ##
## Spotify Launch ##
spotify &>/dev/null &
spotiPid=$!
wait=1
while [ $wait = 1 ]; do
  printf "Waiting for spotify...\n"
  sleep 1
  icon=$(xprop -name 'Spotify - Linux Preview' WM_ICON_NAME &>/dev/null)
  if [ $? == 0 ]; then
    wait=0
  fi
done
##/Spotify Launch ##
ad=0
pause=0
lastIcon=""
while true; do
  num=$(pactl list | grep -E '(^Sink Input)|(media.name = \"Spotify\"$)' | awk '/Spotify/ {print a} {a = $0}' | cut -c 13-)
  if [[ "$num" -eq "" ]]; then
    sleep 0.1
    continue;
  fi
  icon_name=$(xprop -name 'Spotify - Linux Preview' WM_ICON_NAME | awk -F\" '{ print $2; }' );
  if [[ -z "$icon_name" ]]; then
    pause=1
    else
    pause=0
  fi
  if [[ "$lastIcon" = "$icon_name" ]]; then
    sleep 0.2
    continue;
  fi
  echo "$icon_name"
  lastIcon="$icon_name"
  META=$(dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify / org.freedesktop.MediaPlayer2.GetMetadata)
  song_name=$(echo -n "$META" | grep xesam:title -A 1 | grep variant | cut -d \" -f 2)
  song_album=$(echo -n "$META" | grep xesam:album -A 1 | grep variant | cut -d \" -f 2)
  song_artist=$(echo -n "$META" | grep xesam:artist -A 2 | grep string | grep -v xesam | cut -d \" -f 2)
  song_track=$(echo -n "$META" | grep xesam:trackNumber -A 1 | grep variant | awk '{ printf $3; }')
  song_cd=$(echo -n "$META" | grep xesam:discNumber -A 1 | grep variant | awk '{ printf $3; }')
  if [[ "$song_name" && "$icon_name" =~ "$song_name" ]]; then
    if [ "$pause" -eq 0 -a "$ad" -ne 0 ]; then
      # wait 1 second after a commercial
      sleep 1
    fi
    ad=0
    pactl set-sink-input-mute $num no
  else
    ad=1
    pactl set-sink-input-mute $num yes
    song_artist="Spotify"
    song_name="Advert"
    song_album=""
   fi
    Track="$song_track"
    if [ $song_track -lt 10 ]; then
      Track="0$song_track"
    fi
    if [ $song_cd -ne "0" ]; then
      Track=$((($song_cd * 100) + $song_track))
    fi
    Title="$song_artist [$song_album] $Track - $song_name"
    if [ -z "$song_album" ]; then
      Title="$song_artist - $song_name"
    fi
    #Song=$(echo -n "$Title" | perl -pe's/([^-_.~A-Za-z0-9])/sprintf("%%%02X", ord($1))/seg');
     Song=$(echo -n "$Title" | perl -e "\$in=<STDIN>; utf8::decode(\$in); printf(\$in);" | perl -pe's/([^-_.~A-Za-z0-9])/sprintf("%%%02X", ord($1))/seg');
    echo "Title=$Title"
    echo "Song=$Song"
# !!! Uncomment the following wget line ONLY if you have icecast running !!! #
#    wget -O - --tries=1 --user=$IceUser --password=$IcePass --auth-no-challenge -q $BaseURL$Song
    sleep 0.25
done &

wait $spotiPid &&
test -z "`jobs -p`" || kill `jobs -p`

Hey guys,

I'm running Spotify 0.9.4.183 on ElementaryOS v0.2 "Luna", and out of all the pieces of code listed here, the only one that did the trick for me was:

#!/bin/bash

was_paused=0 # if last state was paused
ad=0 # if an ad is probably playing right now

while true; do
num=$(pactl list | grep -E '(^Sink Input)|(media.name = \"Spotify\"$)' | awk '/Spotify/ {print a} {a = $0}' | cut -c 13-)

icon_name=$(xprop -name 'Spotify - Linux Preview' _NET_WM_ICON_NAME | cut -d \" -f 2)
song_name=$(dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify / org.freedesktop.MediaPlayer2.GetMetadata | grep xesam:title -A 1 | grep variant | cut -d \" -f 2)

if [[ "$song_name" && "$icon_name" =~ "$song_name" ]]; then
    if [ "$was_paused" -eq 0 -a "$ad" -ne 0 ]; then
        # wait 1 second after a commercial
        sleep 1
    fi

    ad=0
    pactl set-sink-input-mute $num no
else
    ad=1
    pactl set-sink-input-mute $num yes
fi

if [ "$icon_name" = "Spotify" ]; then
    was_paused=1
else
    was_paused=0
fi

sleep 0.5

done

Unfortunately, whilst it does indeed mute the ads when they come on, it also mutes any tracks that have special characters(i.e. ş,ţ,ă, etc) in their title. It worked fine up until a few weeks ago (meaning it only muted ads), but one day it just started blocking certain tracks as well. Any suggestions ?

I'm sorry I can't give credit to the guy who initially made the above code, but I've tried so many of them, that I forgot whose this one is. And yes, I'm fairly new to the whole linux thing :s

As a fix/replacement for the script for cossmo ( https://gist.github.com/pcworld/3198763/#comment-1192079 )
Includes a fix for
"You have to specify a sink input index and a mute boolean"

LC_ALL ensures nice, parseable output.

#!/bin/bash
LC_ALL=C
## Spotify Launch ##
spotify &>/dev/null &
spotiPid=$!
wait=1
printf "Spotify pid is $spotiPid\n"
while [ $wait = 1 ]; do
  printf "Waiting for spotify...\n"
  sleep 5
  icon=$(xprop -name 'Spotify - Linux Preview' WM_ICON_NAME &>/dev/null)
  if [ $? == 0 ]; then
    wait=0
  fi
done
##/Spotify Launch ##
lastIcon=""
ad=0

xprop -spy -name 'Spotify - Linux Preview' WM_ICON_NAME |
while read -r line ; do
  if [[ ! -d "/proc/$spotiPid" ]]; then
    printf "Spotify exited. Quitting.\n"
    break
  fi
  waitPulse=1
  ## Waiting fo pulseaudio
  while [ $waitPulse -eq 1 ]; do
    num=$(pactl list | grep -E '(^Sink Input)|(media.name = \"Spotify\"$)' | awk '/Spotify/ {print a} {a = $0}' | cut -c 13-)
    if [[ ! -z "$num" ]]; then
      waitPulse=0
      else
      sleep 0.1
    fi
  done
  icon_name=$(echo "$line" | awk -F\" '{ print $2; }' );
  if [[ "$lastIcon" = "$icon_name" ]]; then
    continue;
  fi
  META=$(dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify / org.freedesktop.MediaPlayer2.GetMetadata)
  song_rating=`echo "$META" | grep xesam:autoRating -A 1 | grep variant | awk '{ printf $3; }'`
  song_name=$(echo -n "$META" | grep xesam:title -A 1 | grep variant | cut -d \" -f 2)
  song_artist=$(echo -n "$META" | grep xesam:artist -A 2 | grep string | grep -v xesam | cut -d \" -f 2)

  printf "Rating: $song_rating, $icon_name\n"
  mute=1
  if [[ "$song_name" && "$icon_name" =~ "$song_name"  ]]; then
    mute=0
  fi
  if [[ $mute -eq 0 ]]; then
    if [ $ad -eq 1 ]; then #Post-ad sleep
      sleep 0.5
    fi
    pactl set-sink-input-mute $num no
    ad=0
  else
    pactl set-sink-input-mute $num yes
    ad=1
  fi
done

test -z "`jobs -p`" || kill `jobs -p` 2>/dev/null
exit 0

mute spotify ads (only spanish users)

tested on ubuntu 14.04

#!/bin/bash
fg_black="$(tput setaf 0)"
fg_red="$(tput setaf 1)"
fg_green="$(tput setaf 2)"
fg_yellow="$(tput setaf 3)"
fg_blue="$(tput setaf 4)"
fg_magenta="$(tput setaf 5)"
fg_cyan="$(tput setaf 6)"
fg_white="$(tput setaf 7)"
reset="$(tput sgr0)"


pid=$$

ad=0

#for testing  
c=0
cc=-1

while true ; do  
  echo "${fg_white} $pid ${reset}"  

  if [ $c -eq $cc ]; then
    echo "${fg_red} !!STOP!! $c, $cc ${reset}"  
    break
  fi

  c=$(($c+1))

  num=$(pactl list | grep -E '(^Entrada)|(media.name = \"Spotify\"$)' | awk '/Spotify/ {print a} {a = $0}' | cut -c 21-)

  icon_name=$(xprop -name 'Spotify - Linux Preview' WM_ICON_NAME | awk -F\" '{ print $2; }' );


  META=$(dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify / org.freedesktop.MediaPlayer2.GetMetadata)
  song_name=$(echo -n "$META" | grep xesam:title -A 1 | grep variant | cut -d \" -f 2)
  song_artist=$(echo -n "$META" | grep xesam:artist -A 2 | grep string | grep -v xesam | cut -d \" -f 2)

  mute=1

  echo "${fg_green} $icon_name${reset}"  

  if [[ $icon_name == *$song_artist* ]] 
    then
      echo "${fg_green} Artista OK! ${reset}"
    if [[ $icon_name == *$song_cancion* ]]
      then
        echo "${fg_green} Cancion OK! ${reset}"
        mute=0
      else
        echo "${fg_red} Cancion ERROR! ${reset}"
    fi
  else
    echo "${fg_red} Artista ERROR! ${reset}"
  fi

  sleep 0.5
  if [ $mute -eq 0 ]; then
    if [ $ad=1 ]; then #Post-ad sleep
      sleep 0.5
    fi
    echo "${fg_blue} !NO-MUTE! ${reset}"
    pactl set-sink-input-mute $num no
    ad=0
  else
    echo "${fg_blue} !MUTE! ${reset}"
    pactl set-sink-input-mute $num yes
    ad=1
  fi
done &

Thank you for your prompt reply, AmpGod! Unfortunately, even with the script you provided, the outcome stays the same: tracks whose titles contain special characters get muted. Maybe there's something wrong I'm doing: I moved the script in the spotify folder and use it to launch the app instead of the default executable O_O

hi i'm trying to let the script play a radiostream via vlc.
it starts the stream and mutes spotify whenever an add-break appears but i always have to kill the vlc process by killing the running spotify-admute-script and then restart the script.

If i start the radiostream (cvlc URL) in a terminal i can easily kill it with pkill vlc whenever i want.
hopefully you can help me to get this running.
here's the hint i used: https://gist.github.com/pcworld/3198763/#comment-584571

and here's my mute-script:

#!/bin/bash


was_paused=0 # if last state was paused
ad=0 # if an ad is probably playing right now

while true; do
    num=$(LC_ALL=C pactl list | grep -E '(^Sink Input)|(media.name = \"Spotify\"$)' | awk '/Spotify/ {print a} {a = $0}' | cut -c 13-)

    icon_name=$(xprop -name 'Spotify - Linux Preview' _NET_WM_ICON_NAME | cut -d \" -f 2)
    song_name=$(dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify / org.freedesktop.MediaPlayer2.GetMetadata | grep xesam:title -A 1 | grep variant | cut -d \" -f 2)

    if [[ "$song_name" && "$icon_name" =~ "$song_name" ]]; then
        if [ "$was_paused" -eq 0 -a "$ad" -ne 0 ]; then
            # wait 1 second after a commercial
            sleep 1
            pkill vlc
        fi

        ad=0
        pkill vlc
        pactl set-sink-input-mute $num no
    else
        ad=1
        pactl set-sink-input-mute $num yes
        cvlc ~/Downloads/BassDrive.pls
    fi

    if [ "$icon_name" = "Spotify" ]; then
        was_paused=1
          pkill vlc
    else
        was_paused=0
    fi

    sleep 0.5
done

thx :)

okay, cause i'm quite new to linux, bash, ... etc. i didn't really thought about what i'm doing with the script. since i figured out whats happening there i added the variable vlc_running and changed the first if-fi-block to:

    if [[ "$song_name" && "$icon_name" =~ "$song_name" ]]; then
        if [ "$was_paused" -eq 0 -a "$ad" -ne 0 ]; then
            # wait 1 second after a commercial
            sleep 1
        fi
              #checks if vlc is still running then kills it
        if [ "$vlc_running" -eq 1 ]; then
            pkill vlc
            vlc_running=0
        fi

        ad=0
        pactl set-sink-input-mute $num no
    else
        ad=1
        pactl set-sink-input-mute $num yes

        if [ "$vlc_running" -eq 0 ]; then
            cvlc ~/Downloads/BassDrive.pls &
            vlc_running=1
        fi
    fi

now everything's working as expected...
but is there any better way to do this? i mean is it bad what i did there (from a programmers perspective)?
anything you would do different? i'm just trying to get some input :)

I used this script and the custom while loop in the first comment, and now Spotify will not unmute. Any song I play, there is no sound coming from Spotify. I tried uninstalling and reinstalling Spotify and re-running the script, but no success. Help please!

epleaner:
Your spotify is muted in the pulseaudio volume control. Open pulseaudio volume control, select playback tab, and click the speaker icon near spotify. It will unmute it.

Here's a rewrite of my script. It now relies on DBus information rather than the icon name. (It uses icon name to only monitor when spotify is paused or when spotify changes)
Script automatically kicks spotify up and waits until its ready.

Script includes the support for icecast audio streamer and a trick to keep spotify playing if it pauses for too long.

#!/bin/bash
## Config ##
IceUser="IceCast Username"
IcePass="IceCast password"
IceMount="%2Fmystream.mp3"
#^- Location of the icecast stream - %2F = /
BaseURL="http://localhost:8000/admin/metadata?mount=$IceMount&mode=updinfo&song="
#^- Where icecast itself is - localhost port 8000 is the default
##/Config ##
## Spotify Launch ##
spotify &>/dev/null &
spotiPid=$!
wait=1
printf "Spotify pid is $spotiPid\n"
while [ $wait = 1 ]; do
  printf "Waiting for spotify...\n"
  sleep 5
  icon=$(xprop -name 'Spotify - Linux Preview' WM_ICON_NAME &>/dev/null)
  if [ $? == 0 ]; then
    wait=0
  fi
done
##/Spotify Launch ##
WAKEUPS=0
POKECOUNT=0
PREVTITLE=""
COUNT=0
while [ 1 ] ; do
  if [[ ! -d "/proc/$spotiPid" ]]; then
    printf "Spotify exited. Quitting.\n"
    break
  fi
  TITLE=`xprop -name 'Spotify - Linux Preview' WM_ICON_NAME | awk -F\" '{ print $2; }'`
  NEW=0
  AD=0
  PAUSE=0
  if [ "$TITLE" != "$PREVTITLE" ]; then
    META=$(dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify / org.freedesktop.MediaPlayer2.GetMetadata)
    song_name=$(echo -n "$META" | grep xesam:title -A 1 | grep variant | cut -d \" -f 2)
    song_album=$(echo -n "$META" | grep xesam:album -A 1 | grep variant | cut -d \" -f 2)
    song_artist=$(echo -n "$META" | grep xesam:artist -A 2 | grep string | grep -v xesam | cut -d \" -f 2)
    song_track=$(echo -n "$META" | grep xesam:trackNumber -A 1 | grep variant | awk '{ printf $3; }')
    song_cd=$(echo -n "$META" | grep xesam:discNumber -A 1 | grep variant | awk '{ printf $3; }')
    song_rating=$(echo "$META" | grep xesam:autoRating -A 1 | grep variant | awk '{ printf $3; }')
    PREVTITLE="$TITLE"
    printf "\n\nWakeups=$WAKEUPS, Rating=$song_rating\n"
    POKECOUNT=0
    NEW=1
  fi
  if [ "$song_rating" == "" ]; then
    printf " "
    POKECOUNT=$(($POKECOUNT + 1))
    AD=1
  fi
  if [ "$TITLE" ==  "Spotify" ]; then
    printf " "
    POKECOUNT=$(($POKECOUNT + 1))
    AD=1
    PAUSE=1
  fi
  if [ $POKECOUNT -gt 600 ]; then
    WAKEUPS=$(($WAKEUPS + 1))
    #dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.PlayPause >/dev/null
    #^- Uncomment if you want to keep spotify constantly playing.
    POKECOUNT=0
  fi
  if [ "$NEW" == "1" ]; then
    ## Pulseaudio wait ##
    if [ "$PAUSE" == "0" ]; then
      waitPulse=1
      while [ $waitPulse -eq 1 ]; do
        num=$(pactl list | grep -E '(^Sink Input)|(media.name = \"Spotify\"$)' | awk '/Spotify/ {print a} {a = $0}' | cut -c 13-)
        if [[ ! -z "$num" ]]; then
          waitPulse=0
          else
          sleep 0.1
        fi
      done
    fi
    ##/Pulseaudio wait ##
    if [ "$AD" == "1" ]; then
      pactl set-sink-input-mute $num yes
      song_artist="Spotify"
      song_name="Advert"
      song_album=""
    else
      pactl set-sink-input-mute $num no
    fi
    ## IceCast update ##
    if [ ! -z "$song_rating" ]; then
      if [ $song_cd -gt 0 ]; then
        Track=$((($song_cd * 100) + $song_track))
        else
        Track=$(($song_track + 100))
      fi
      Title="$song_artist [$song_album] $Track - $song_name"
    fi
    if [ -z "$song_album" ]; then
      Title="$song_artist - $song_name"
    fi
    Song=$(echo -n "$Title" | perl -e "\$in=<STDIN>; utf8::decode(\$in); printf(\$in);" | perl -pe's/([^-_.~A-Za-z0-9])/sprintf("%%%02X", ord($1))/seg');
    printf "$Title ."
    #wget -O /dev/null --tries=1 --user=$IceUser --password=$IcePass --auth-no-challenge -q $BaseURL$Song
    #^- IceCast update. Remove comment only if you have a working icecast server
  fi
  ## Animation ##
  COUNT=$(($COUNT + 1))
  if [ "$COUNT" == "1" ]; then printf "\b-"; fi
  if [ "$COUNT" == "2" ]; then printf "\b\\"; fi
  if [ "$COUNT" == "3" ]; then printf "\b|"; fi
  if [ "$COUNT" == "4" ]; then printf "\b/"; fi
  if [ "$COUNT" == "5" ]; then COUNT=1; printf "\b-"; fi
  ##/Animation ##
  unset META
  sleep 0.2
done

test -z "`jobs -p`" || kill `jobs -p`
exit 0

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.