Auto muting when spotify plays an advertisement

I did not buy spotify premium for this year (yet?). I’m not sure if it is just me or it is happening for everybody, but it looks like for some reason I’m bombarded with ads. I get 2–3 ads between every 3–4 songs. They are boring, repetitive and even sometimes in other languages. I understand that the idea of ads is to push people to pay, so I guess they are successful in that regard.

Note (from me in the future): I am a paid subscriber for spotify. But still there is value in working on hacks like these for fun & learning!

So, lets make Linux mute audio for us when a spotify advert is playing!

Understanding d-bus and MPRIS

Some context before I start showing how I solved this. There is a message bus system in linux called d-bus. d-bus is a free desktop standard and is behind almost all the communication which happens between programs.

One more important piece is called MPRIS. MPRIS stands for Media Player Remote Interfacing Specification. It is a standard d-bus interface which aims to produce common programmatic API for controlling media players (This is straight up copied from the spec). This is also a freedesktop spec. This is the beauty of specs and the free desktop, all the famous desktops adhere to this standard and it is well documented.

Recognizing when spotify plays an advert

All we have to do is have a small function run every second, check what media is playing by name. If it turns out to be an "Advertisement", then we just mute the audio source. I am running ALSA (Advanced Linux Sound Architecture) in the background and it can be controlled by amixer. Most probably, your linux flavour is running this too.

The important command to understand is in line two, Let’s break it down.

  • This sends a command to d-bus asking for mpris properties of spotify. This will return a bunch of values like track ID, length, album, albumArtist etc. Run this command when running spotify to get a taste of what data is available for us to play with. (ref)
  • Also forwarding the stderr to /dev/null, using 2>/dev/null. The "right" way to do it is to check if spotify is even running and if yes, ping the d-bus. But that is too many commands for something which runs every second. So whenever spotify is not running, the command will error out and the error will be sent to the void.
  • sed -n '/title/{n;p}' The -n flag suppress all output that isn't explicitly printed. n in the flower brackets moves to the next line andp prints it explicitly.(ref)
  • At this point we will be left with variant string "<media name>". cut is used with a delimiter(-d) of " and the first (zero ordered) piece is taken out using -f

Now, the media title is compared to string "Advertisement" (that's what spotify seems to send to MPRIS if it is playing an ad). If true, then we mute the sound using amixer -q -D pulse sset Master mute else unmute.

Finally we need to place it somewhere such that it runs on startup.

Not in .bashrc/.zshrc, because they only run when the shell starts. To run it when the system starts, this trigger should be placed in.profile.

Let us add a loop in.profile to run the function every second.

That’s it! Now whenever spotify plays an ad, the audio is muted automatically.

Why can I not mute audio at all!?

The previous solution works, but is a very bad take. Every second, it checks if the current playing music is named “Advertisement” and if it is then mutes it. But the problem is, now the audio can never be manually muted. Since every time audio is manually muted, the next second the script runs -> sees the media name is not Advertisement and un-mutes!

So one sanity check to add is to make sure spotify is actually running and then check if the music played by spotify is an ad and mute it. Let us look at the modified function now.

Two booleans, first (IS_MUTE) checks if the audio is muted and second (IS_SPOTIFY_AD) checks if the current playing spotify song name is called “Advertisement”. First check is if Spotify is even playing, later if not muted and spotify ad then mute else unmute. This ensures that when Spotify is not playing, mute works as expected.

But there are problems to this as well. If spotify is paused and Firefox is playing audio, then mute no longer works as expected. You also cannot mute a song when spotify is playing 😆

The ideal way would be to just deal with the spotify audio stream and manage it.

The solution

Instead of dealing with the entire sound card, we now deal only with spotify input sink. Get the right pulse audio input sink ID and mute that. Pulse Audio is the sound server distributed by the free desktop.

I’ll be honest, I have no idea what the Perl magic is in the command which retrieves the spotify sink ID. I just copied it from stackoverflow and did a grep | cut to get the sink number. Later on when an Advertisement is playing, I’m using the pactl to mute the input audio sink. This seems to work as expected.

Bash with the unix utilities is a killer combo, I should probably write an article explaining the basics of bash and some handy unix utilities.

Originally published at https://bharatkalluri.com.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store