Last active
September 7, 2022 21:51
-
-
Save hoehermann/8b6fa0682bd9192e835d1b7ba8daa4b6 to your computer and use it in GitHub Desktop.
This script mutes Spotify when it plays advertisements.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# encoding: utf-8 | |
import sys | |
import dbus | |
import dbus.mainloop.glib | |
import subprocess | |
import time | |
import re | |
from gi.repository import GLib | |
# copied from https://github.com/avindra/pacmd-python | |
def parseList(output): | |
lines = output.split('\n') | |
first = lines.pop(0) | |
if first.startswith('Unknown command'): | |
raise Exception(first) | |
data = {} | |
currentItem = {} | |
currentIndex = -1 | |
patternNewItem = re.compile('(\* )?index: (\d+)') | |
patternKeyValue = re.compile('\t*([^:]+):(?: (.+))?') | |
patternEnumerating = re.compile('^\tproperties:') | |
patternProps = re.compile('(\S+) = "(.+)"') | |
enumeratingProps = None | |
lastKey = None | |
for line in lines: | |
matchNewItem = patternNewItem.search(line) | |
matchKeyValue = patternKeyValue.search(line) | |
matchEnumerating = patternEnumerating.search(line) | |
if enumeratingProps: | |
matchProps = patternProps.search(line) | |
if matchProps: | |
enumeratingProps[matchProps.group(1)] = matchProps.group(2) | |
continue | |
else: # reset | |
currentItem['properties'] = enumeratingProps | |
enumeratingProps = None | |
if matchEnumerating: | |
enumeratingProps = { 'device-api' : None } | |
elif matchNewItem: | |
isActive = matchNewItem.group(1) == '* ' | |
index = matchNewItem.group(2) | |
# Finalize object and reset | |
if currentIndex != -1: | |
data[currentIndex] = currentItem | |
currentItem = {} | |
currentIndex = index | |
if isActive: | |
data['activeItem'] = index | |
elif matchKeyValue: | |
parsedKey = matchKeyValue.group(1).strip() | |
parsedValue = matchKeyValue.group(2) | |
# skip until we're out of "ports". | |
# not currently supported | |
if lastKey == 'ports' and parsedKey != 'active port': | |
continue | |
lastKey = parsedKey | |
currentItem[parsedKey] = parsedValue | |
elif lastKey and lastKey != 'ports': # If it gets to here, we can assume its a multiline attr | |
currentItem[lastKey] += re.sub('^\s+', '\n', line) | |
# Last item will need to be pushed manually | |
data[currentIndex] = currentItem | |
return data | |
def pacmd_list_sink_inputs(): | |
p = subprocess.Popen(['pacmd','list-sink-inputs'], stdout=subprocess.PIPE, encoding='utf-8') | |
out, err = p.communicate() | |
return parseList(out) | |
def pacmd_set_sink_input_mute(index, mutestate): | |
p = subprocess.Popen(['pacmd','set-sink-input-mute', index, mutestate]) | |
out, err = p.communicate() | |
def pulse_mute_spotify(mutestate): | |
inputs = pacmd_list_sink_inputs() | |
# spotify may allocate more than one output | |
spotify_indices = [ | |
index for index, sink in inputs.items() | |
if 'properties' in sink and sink['properties']['application.process.binary'] == 'spotify' | |
] | |
for spotify_index in spotify_indices: | |
pacmd_set_sink_input_mute(spotify_index, mutestate) | |
print('Set mutestate to %s for %s'%(mutestate, str(spotify_indices))) | |
def is_advert(metadata): | |
""" Whether the current song is an advertisement. """ | |
if 'Metadata' in metadata: | |
m = metadata['Metadata'] | |
artist = m['xesam:artist'][0] | |
return artist == "" | |
else: | |
return False | |
def propertiesChanged_handler(sender=None, metadata=None, sig=None): | |
time.sleep(0.5) # event comes a bit earlier than actual content change | |
is_ad = is_advert(metadata) | |
pulse_mute_spotify('1' if is_ad else '0') | |
def main(): | |
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) | |
bus = dbus.SessionBus() | |
try: | |
remote_object = bus.get_object( | |
"org.mpris.MediaPlayer2.spotify", | |
"/org/mpris/MediaPlayer2" | |
) | |
change_manager = dbus.Interface( | |
remote_object, | |
'org.freedesktop.DBus.Properties' | |
) | |
change_manager.connect_to_signal( | |
"PropertiesChanged", | |
propertiesChanged_handler | |
) | |
except dbus.exceptions.DBusException as dbe: | |
if (dbe.get_dbus_name() == "org.freedesktop.DBus.Error.ServiceUnknown"): | |
print("Please start Spotify first. (%s)"%(dbe.get_dbus_message())) | |
sys.exit(1) | |
loop = GLib.MainLoop() | |
loop.run() | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment