Skip to content

Commit

Permalink
update to v2.0.0. Introduced rudimentary support for Spotify v1.0 and…
Browse files Browse the repository at this point in the history
… higher.
  • Loading branch information
Max Demian committed Sep 5, 2015
1 parent 689c790 commit 43dd560
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 54 deletions.
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
# blockify
Blockify is a linux only application that allows you to automatically mute songs and advertisements in Spotify.

**Blockify currently does not support Spotify version 1.0.0 and higher.**

## Installation
##### Dependencies
Before installing blockify, please make sure you have the appropriate dependencies installed.
- Mandatory: pygtk alsa-utils gstreamer0.10-python python2-wnck python2-dbus
- Mandatory: pygtk alsa-utils gstreamer0.10-python python-wnck python2-dbus
- Optional (but highly recommended): pulseaudio python2-docopt
- Installation tools: python2-pip (preferred) OR python2-setuptools

Expand Down Expand Up @@ -135,6 +133,7 @@ http://skyserver5.skydisc.net:8000
You can use relative and absolute paths as well as basically any audio source/format, as long as you have the respective gstreamer codec installed.

## Changelog
- v2.0.0 (2015-09-05): (prerelease) Added rudimentary support for Spotify v1.0 and higher. Fixed autoplay option.
- v1.9.0 (2015-08-15): Fix [issue #52](https://github.com/mikar/blockify/issues/52), introduce autoplay option and change start_spotify option to boolean type
- v1.8.8 (2015-07-11): Fix [issue #46](https://github.com/mikar/blockify/issues/46) and [issue #47](https://github.com/mikar/blockify/issues/47)
- v1.8.7 (2015-06-11): Pressing play will now properly pause interlude music before resuming spotify playback.
Expand Down
66 changes: 41 additions & 25 deletions blockify/blockify.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ def __init__(self, blocklist):
self.update_interval = util.CONFIG["cli"]["update_interval"]
self.unmute_delay = util.CONFIG["cli"]["unmute_delay"]
self.pulse_unmuted_value = ""
self.song_delimiter = " - " # u" \u2013 "
self.found = False
self.current_song = ""
self.previous_song = ""
Expand Down Expand Up @@ -77,11 +78,11 @@ def start_spotify_if_necessary(self):
if self.check_for_spotify_process():
return
log.error("No spotify process found.")

if not util.CONFIG["general"]["start_spotify"]:
log.info("Exiting. Bye.")
sys.exit()

self.start_spotify()
if not self.check_for_spotify_process():
log.error("Failed to start Spotify!")
Expand All @@ -102,14 +103,14 @@ def initialize_pulse_unmuted_value(self):
"mute behaviour. A possible fix is to replace the "
"value of unmuted_value in blockify.py with your "
"translation of 'no', e.g. 'tak' in polish.")
self.pulse_unmuted_value = unmuted_value
self.pulse_unmuted_value = unmuted_value


def initialize_mute_method(self):
"""Determine if we can use sinks or have to use alsa."""
try:
devnull = open(os.devnull)
pacmd_out = subprocess.check_output(["pacmd", "list-sink-inputs"], stderr=devnull)
subprocess.check_output(["pacmd", "list-sink-inputs"], stderr=devnull)
self.mutemethod = self.pulsesink_mute
log.debug("Mute method is pulse sink.")
except (OSError, subprocess.CalledProcessError):
Expand All @@ -125,7 +126,7 @@ def install_locale(self):
current_locale, encoding = locale.getdefaultlocale()
pulseaudio_domain = 'pulseaudio'
localedir = gettext.find(pulseaudio_domain, languages=[current_locale])
localedir = localedir[:localedir.find('locale/')]+'locale'
localedir = localedir[:localedir.find('locale/')] + 'locale'
locale = gettext.translation(pulseaudio_domain, localedir=localedir, languages=[current_locale])
locale.install()

Expand Down Expand Up @@ -154,18 +155,13 @@ def start_spotify(self):
if util.CONFIG["general"]["start_spotify"]:
log.info("Starting Spotify ...")
null = open('/dev/null', 'w')
spid = subprocess.Popen(['/usr/bin/spotify'], stdout=null, stderr=null) #.pid
for i in range(20):
subprocess.Popen(['/usr/bin/spotify'], stdout=null, stderr=null) # .pid
for _ in range(20):
time.sleep(1)
spotify_is_running = self.check_for_spotify_process()
if spotify_is_running:
log.info("Spotify launched!")
break

#if spid:
# log.info("Spotify launched!")
# time.sleep(10)


def init_channels(self):
channel_list = ["Master"]
Expand All @@ -190,21 +186,21 @@ def start(self):
self.bind_signals()
# Force unmute to properly initialize unmuted state
self.toggle_mute()

gtk.timeout_add(self.update_interval, self.update)
# Delay autoplayback until self.spotify_is_playing was called at least once.
gtk.timeout_add(self.update_interval+100, self.start_autoplay)
gtk.timeout_add(self.update_interval + 100, self.start_autoplay)

log.info("Blockify started.")

gtk.main()


def start_autoplay(self):
log.debug("Autoplay is activated.")
if not self.spotify_is_playing():
if self.autoplay:
log.debug("Autoplay is activated.")
log.info("Starting Spotify autoplayback.")
self.dbus.playpause()
self.dbus.play()
return False


Expand Down Expand Up @@ -232,7 +228,7 @@ def find_ad(self):
"Main loop. Checks for ads and mutes accordingly."
self.previous_song = self.current_song
self.current_song = self.get_current_song()
self.song_status = self.dbus.get_song_status()
# self.song_status = self.dbus.get_song_status()

# Manual control is enabled so we exit here.
if not self.automute:
Expand Down Expand Up @@ -275,8 +271,9 @@ def ad_found(self):
def current_song_is_ad(self):
"Compares the wnck song info to dbus song info."
try:
is_ad = self.current_song != self.dbus.get_song_artist() + u" \u2013 " + self.dbus.get_song_title()
return self.spotify_is_playing() and is_ad
dbus_song = self.dbus.get_song_artist() + self.song_delimiter + self.dbus.get_song_title()
is_ad = self.current_song != dbus_song
return is_ad
except TypeError as e:
# Spotify has technically stopped playing and sending dbus
# metadata so we get NoneType-errors.
Expand All @@ -291,6 +288,23 @@ def unmute_with_delay(self):
self.toggle_mute()
return False

def find_spotify_window_wmctrl(self):
spotify_window = []
try:
pipe = subprocess.Popen(['wmctrl', '-lx'], stdout=subprocess.PIPE).stdout
window_list = pipe.read().split("\n")
for window in window_list:
if (window.find("spotify.Spotify") >= 0):
# current_song = " ".join(window.split()[5:])
spotify_window.append(window)
break

except OSError:
print "wmctrl needs to be installed"
sys.exit(1)

return spotify_window


def find_spotify_window(self):
"Libwnck list of currently open windows."
Expand All @@ -308,11 +322,11 @@ def find_spotify_window(self):
def get_current_song(self):
"Checks if a Spotify window exists and returns the current songname."
song = ""
spotify_window = self.find_spotify_window()
spotify_window = self.find_spotify_window_wmctrl()

if spotify_window:
try:
song = " ".join(spotify_window[0].split()[2:]).decode("utf-8")
song = " ".join(spotify_window[0].split()[4:]).decode("utf-8")
except Exception as e:
log.debug("Could not match spotify pid to sink pid: %s", e, exc_info=1)

Expand All @@ -326,6 +340,8 @@ def block_current(self):

def unblock_current(self):
if self.current_song:
if self.use_interlude_music:
self.player.pause()
song = self.blocklist.find(self.current_song)
if song:
self.blocklist.remove(song)
Expand Down Expand Up @@ -460,12 +476,12 @@ def signal_unblock_received(self, sig, hdl):
def signal_prev_received(self, sig, hdl):
log.debug("Signal {} received. Playing previous interlude.".format(sig))
self.prev()


def signal_next_received(self, sig, hdl):
log.debug("Signal {} received. Playing next song.".format(sig))
self.next()


def signal_playpause_received(self, sig, hdl):
log.debug("Signal {} received. Toggling play state.".format(sig))
Expand Down
29 changes: 14 additions & 15 deletions blockify/blockifyui.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,15 +413,15 @@ def start(self):
"Start the main update routine."
self.b.toggle_mute()
self.bind_signals()

# Start and loop the main update routine once every X ms.
# To influence responsiveness or CPU usage, decrease/increase self.update_interval.
gtk.timeout_add(self.update_interval, self.update)
# Delay autoplayback until self.spotify_is_playing was called at least once.
gtk.timeout_add(self.update_interval+100, self.b.start_autoplay)
gtk.timeout_add(self.update_interval + 100, self.b.start_autoplay)

log.info("Blockify-UI started.")

gtk.main()

def stop(self, *args):
Expand Down Expand Up @@ -543,7 +543,7 @@ def update_labels(self):
if not self.b.found:
self.albumlabel.set_text(self.b.dbus.get_song_album())
else:
self.albumlabel.set_text("(blocked)")
self.albumlabel.set_text("N/A")

artist, title = self.format_current_song()
self.artistlabel.set_text(artist)
Expand All @@ -559,10 +559,10 @@ def update_buttons(self):
self.toggle_block_btn.set_label("Block")
self.set_title("Blockify")

if self.b.spotify_is_playing() and self.b.current_song:
self.toggleplay_btn.set_label("Pause")
else:
self.toggleplay_btn.set_label("Play")
# if self.b.current_song: # and self.b.spotify_is_playing()
# self.toggleplay_btn.set_label("Pause")
# else:
# self.toggleplay_btn.set_label("Play")

if self.coverimage.get_visible():
self.toggle_cover_btn.set_label("Hide Cover")
Expand Down Expand Up @@ -707,7 +707,7 @@ def on_autoresume(self, widget):
if not self.b.player.autoresume:
self.b.player.autoresume = True
self.b.player.manual_control = False
if not self.b.found and not self.b.spotify_is_playing():
if not self.b.found: # and not self.b.spotify_is_playing():
self.b.dbus.playpause()
else:
self.b.player.autoresume = False
Expand All @@ -716,8 +716,7 @@ def disable_interlude_box(self):
self.b.use_interlude_music = False
self.interlude_box.hide()
self.b.player.pause()
if not self.b.spotify_is_playing():
self.b.dbus.playpause()
self.b.dbus.play()
self.toggle_interlude_btn.set_label("Enable player")
self.restore_size()

Expand Down Expand Up @@ -758,13 +757,13 @@ def on_interlude_tag_changed (self, bus, message):
def toggle_interlude(self):
if not self.b.player.is_playing():
self.b.player.manual_control = False
self.b.dbus.pause()
self.b.player.play()
else:
self.b.player.manual_control = True
self.b.player.pause()
if not self.b.found and (not self.b.spotify_is_playing() or
not self.b.current_song):
self.b.dbus.playpause()
if not self.b.found and not self.b.current_song: # or not self.b.spotify_is_playing()
self.b.dbus.play()

def on_play_interlude_btn(self, widget):
"Interlude play button."
Expand Down
17 changes: 7 additions & 10 deletions blockify/interludeplayer.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def on_about_to_finish(self, player):
"Song is ending. What do we do?"
self.queue_next()
log.debug("Interlude song finished. Queued: {}.".format(self.get_current_uri()))
if not self.autoresume and not self.b.spotify_is_playing():
if not self.autoresume: # and not self.b.spotify_is_playing():
self.pause()
self.b.dbus.playpause()

Expand Down Expand Up @@ -141,22 +141,19 @@ def try_resume_spotify_playback(self, ignore_player=False):
log.info("Trying to resume spotify playback.")
if (self.is_playing() or ignore_player) and not self.b.found:
self.pause()
if not self.b.spotify_is_playing():
self.b.dbus.playpause()
self.b.dbus.play()

def resume_spotify_playback(self):
if not self.b.found:
if not self.b.spotify_is_playing():
self.b.dbus.playpause()
self.pause()
self.b.dbus.play()
log.info("Switched from radio back to Spotify.")
return False
return True
else:
log.info("Tried to switch from radio to Spotify but commercial still playing. Will resume when commercial ends.")
self.temp_autoresume = True
return False

return True
return False

def playpause(self):
if self.is_playing():
Expand Down Expand Up @@ -192,8 +189,8 @@ def toggle_music(self):
if self.autoresume or self.temp_autoresume:
self.pause()
self.temp_autoresume = False
elif self.b.spotify_is_playing():
self.b.dbus.playpause()
else:
self.b.dbus.play()

def is_playing(self):
return self.player.get_state()[1] == gst.STATE_PLAYING
Expand Down
2 changes: 1 addition & 1 deletion blockify/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
except ImportError:
log.error("ImportError: Please install docopt to use the CLI.")

VERSION = "1.9.0"
VERSION = "2.0.0"
CONFIG = None
CONFIG_DIR = os.path.expanduser("~/.config/blockify")
CONFIG_FILE = os.path.join(CONFIG_DIR, "blockify.ini")
Expand Down

0 comments on commit 43dd560

Please sign in to comment.