From f66260435ad7036b5822a3ef8a27fc3b8a24da67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=2EFernando=20S=C3=A1nchez?= Date: Fri, 5 Apr 2013 17:56:13 +0200 Subject: [PATCH] Added scripts to control spotify --- icon_spotify.png | Bin 0 -> 15487 bytes one-tmux | 2 +- spotify-remote.py | 419 ++++++++++++++++++++++++++++++++++++++++++++++ spotify-remote.sh | 114 +++++++++++++ 4 files changed, 534 insertions(+), 1 deletion(-) create mode 100644 icon_spotify.png create mode 100755 spotify-remote.py create mode 100755 spotify-remote.sh diff --git a/icon_spotify.png b/icon_spotify.png new file mode 100644 index 0000000000000000000000000000000000000000..a640f7d97f7bee3d25e9ad31a686433deeed1b42 GIT binary patch literal 15487 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 B4i*3a literal 0 HcmV?d00001 diff --git a/one-tmux b/one-tmux index 9c8f57c..7b063c3 100755 --- a/one-tmux +++ b/one-tmux @@ -1,5 +1,5 @@ #!/bin/bash -TERMINAL_EMULATOR='xfce4-terminal' +TERMINAL_EMULATOR='urxvt' tab=1 pgrep -l -u "$USER" -f "$TERMINAL_EMULATOR" | egrep -v "/bin/zsh|/bin/bash|/bin/sh" | grep -vq "$$" if [ $? != "0" ] diff --git a/spotify-remote.py b/spotify-remote.py new file mode 100755 index 0000000..e0a7dbf --- /dev/null +++ b/spotify-remote.py @@ -0,0 +1,419 @@ +#!/usr/bin/python + +# Spoify-remote +# Modified version of Spotify-notify that runs once when invoked instead of looping. +# +# v0.6d (28th aug 11) +# by JonW (jon.neverwinter@gmail.com) +# patched 20110907 by Jansen Price (sumpygump@gmail.com) +# patched 20120729 by Jansen Price (sumpygump@gmail.com) and brandl.matthaeus +# modified 20130405 by Fernando Sánchez (balkian@gmail.com) +# +# Original by SveinT (sveint@gmail.com) +# up to v0.5.2 (27th jan 11) + + +import dbus + +import gobject, gtk, os, tempfile, sys, time, re, indicate, urllib2 +from optparse import OptionParser +from subprocess import * + +# The url to use when fetching spotify track information. +SPOTIFY_OPEN_URL = "http://open.spotify.com/track/" + +# The path to this application's directory. +APPLICATION_DIR = sys.path[0] + "/" + +# The file path to spotify. If empty, it will try to auto detect. +SPOTIFY_PROCESS_NAME = 'spotify' + +# How often to check if spotify has been closed (in milliseconds). +SPOTIFY_CLOSED_CHECK = 20000 + +class SpotifyNotify(): + + spotifyPath = '' + + tryToReconnect = False + + tmpfile = False + + def __init__(self, debugger): + self.debug = debugger + self.spotifyservice = False + + self.prev = 0 + self.new = False + self.prevMeta = {} + self.notifyid = 0 + + self.connect() + + def __del__(self): + if SpotifyNotify and SpotifyNotify.tmpfile: + SpotifyNotify.tmpfile.close() + + def connect(self): + self.debug.out("Connecting to spotify.") + self.bus = dbus.Bus(dbus.Bus.TYPE_SESSION) + + try: + self.spotifyservice = self.bus.get_object( + 'com.spotify.qt', + '/org/mpris/MediaPlayer2' + ) + SpotifyNotify.tryToReconnect = False + except Exception, e: + self.spotifyservice = False + self.debug.out("Failed to connect.") + self.debug.out(e) + + def executeCommand(self, key): + if not key: + return + + self.connect() + self.debug.out("Running command: {0}".format(key)) + self.cmd = self.spotifyservice.get_dbus_method(key, 'org.mpris.MediaPlayer2.Player') + self.cmd() + + def pollChange(self): + try: + self.spotifyservice = self.bus.get_object('com.spotify.qt', '/') + self.cmd = self.spotifyservice.get_dbus_method( + 'GetMetadata', + 'org.freedesktop.MediaPlayer2' + ) + self.new = self.cmd() + except Exception, e: + self.debug.out('Spotify service not connected.') + SpotifyNotify.tryToReconnect = True + + if (self.prev != self.new): + self.trackChange(self.new) + self.prev = self.new + + return 1 + + def trackChange(self, *trackChange): + if not trackChange[0]: + return + + self.prev = trackChange[0] + + trackInfo = {} + trackMap = { + 'artist' : 'xesam:artist', + 'album' : 'xesam:album', + 'title' : 'xesam:title', + 'year' : 'xesam:contentCreated', + 'trackhash' : 'mpris:trackid', + 'arturl' : 'mpris:artUrl' + } + + # Fetch the track information for the notification window. + for key in trackMap: + if not trackMap[key] in trackChange[0]: + continue + piece = trackChange[0][trackMap[key]] + if key == 'year': + piece = str(piece[:4]) + elif isinstance(piece, list): + piece = ", ".join(piece) + + if not isinstance(piece, str): + piece = str(piece) + + trackInfo[key] = piece.encode('utf-8') + + if not self.prevMeta\ + or not SpotifyNotify.tmpfile\ + or 'iconfilename' not in self.prevMeta\ + or self.prevMeta['artist'] != trackInfo['artist']\ + or self.prevMeta['album'] != trackInfo['album']: + trackInfo['iconfilename'] = self.retrieveCoverImage(trackInfo) + + cover_image = '' + + if 'iconfilename' in trackInfo: + cover_image = trackInfo['iconfilename'] + elif 'iconfilename' in self.prevMeta: + cover_image = self.prevMeta['iconfilename'] + trackInfo['iconfilename'] = cover_image + + if cover_image == '': + cover_image = APPLICATION_DIR + 'icon_spotify.png' + + self.prevMeta = trackInfo + + # Connect to notification interface on DBUS. + self.notifyservice = self.bus.get_object( + 'org.freedesktop.Notifications', + '/org/freedesktop/Notifications' + ) + self.notifyservice = dbus.Interface( + self.notifyservice, + "org.freedesktop.Notifications" + ) + notifyText = "{0}\n{1}".format( + trackInfo['title'], + trackInfo['album'] + ) + if len(trackInfo['year']) > 0: + notifyText += " ({0})".format(trackInfo['year']) + + # Send track change information to stdout + print "Changing track : {0} | {1} | {2} ({3})".format( + trackInfo['artist'], + trackInfo['title'], + trackInfo['album'], + trackInfo['year'] + ) + + # The second param is the replace id, so get the notify id back, + # store it, and send it as the replacement on the next call. + self.notifyid = self.notifyservice.Notify( + "Spotify-notify", + self.notifyid, + cover_image, + trackInfo['artist'], + notifyText, + [], + {}, + 2000 + ) + + def retrieveCoverImage(self, trackInfo): + if 'arturl' in trackInfo: + self.debug.out("Simply retrieving image from {0}".format(trackInfo['arturl'])) + iconfilename = self.fetchCoverImage(trackInfo['arturl']) + else: + #if (trackInfo['trackhash'][0:14] == 'spotify:local:'): + # self.debug.out("Track is a local file. No art available.") + # return '' + + self.debug.out("Attempting to fetch image from spotify") + iconfilename = self.fetchCoverImageSpotify( + trackInfo['artist'], + trackInfo['album'], + trackInfo['trackhash'] + ) + return iconfilename + + def fetchCoverImageSpotify(self, artist, album, trackhash): + try: + trackid = trackhash.split(":")[2] + url = SPOTIFY_OPEN_URL + trackid + tracksite = urllib2.urlopen(url).read() + + # Attempt to get the image url from the open graph image meta tag. + imageurl = False + metaMatch = re.search( + ']*property\s*=\s*["\']og:image["\'][^\>]*/?>', + tracksite + ) + if metaMatch: + contentMatch = re.search( + 'content\s*=\s*["\']([^\"\']*)["\']', + metaMatch.group(0) + ) + if contentMatch: + imageurl = contentMatch.group(1) + + if not imageurl: + self.debug.out("No cover available.") + raise() + + return self.fetchCoverImage(imageurl) + except Exception, e: + self.debug.out("Couldn't fetch cover image.") + self.debug.out(e) + + return '' + + def fetchCoverImage(self, url): + # Close the temporary image file, we are going to make a new one. + if SpotifyNotify.tmpfile: + SpotifyNotify.tmpfile.close() + SpotifyNotify.tmpfile = False + + try: + SpotifyNotify.tmpfile = tempfile.NamedTemporaryFile() + tmpfilename = SpotifyNotify.tmpfile.name + self.debug.out("Album art tmp filepath: {0}".format(tmpfilename)) + + coverfile = urllib2.urlopen(url) + SpotifyNotify.tmpfile.write(coverfile.read()) + SpotifyNotify.tmpfile.flush() + return tmpfilename + except Exception, e: + self.debug.out("Couldn't fetch cover image.") + self.debug.out(e) + + return '' + + @staticmethod + def startSpotify(Debug): + if not SpotifyNotify.spotifyPath: + Debug.out("No spotify process identifier found.") + return + + ident = SpotifyNotify.spotifyPath + Debug.out("Looking for spotify as: {0}".format(ident)) + + procs = SpotifyNotify.checkForProcess( + 'ps x | grep "{0}" | grep -v grep'.format(ident), + Debug + ) + if len(procs): + Debug.out("Spotify process found as: {0}".format(" ".join(procs[0]))) + return + + Debug.out("Starting new Spotify now.") + + FNULL = open('/dev/null', 'w') + spid = Popen([ident], stdout=FNULL, stderr=FNULL).pid + if spid: + Debug.out("Spotify started, pid: {0}.".format(spid)) + else: + Debug.out("Spotify could not be started.") + + @staticmethod + def checkForClosedSpotify(SN, Debug): + if not SpotifyNotify.spotifyPath: + Debug.out("No spotify process identifier found.") + return False + + ident = SpotifyNotify.spotifyPath + Debug.out("Looking for spotify as: {0}".format(ident)) + + procs = SpotifyNotify.checkForProcess( + 'ps x | grep "{0}" | grep -v grep'.format(ident), + Debug + ) + if len(procs): + Debug.out("Spotify process found as: {0}".format(" ".join(procs[0]))) + + if (SpotifyNotify.tryToReconnect): + SN.connect() + + return True + + if SpotifyNotify.tmpfile: + SpotifyNotify.tmpfile.close() + + Debug.out("Spotify has been closed, therefore I die.") + exit(0) + + @staticmethod + def preventDuplicate(Debug): + mypid = os.getpid() + Debug.out("My pid: {0}".format(mypid)) + + proc = SpotifyNotify.checkForProcess('ps -p {0}'.format(mypid), Debug) + if not proc[0][3]: + return + + process = proc[0][3] + search = 'ps -C {0}'.format(process) + + Debug.out("Looking for other processes named: {0}".format(process).strip()) + + if process == 'python': + if not sys.argv[0]: + Debug.out("Process started using python, cannot determine script name.") + return + + search = 'ps ax | grep "python {0}" | grep -v grep'.format(sys.argv[0]) + + for line in SpotifyNotify.checkForProcess(search, Debug): + if int(line[0]) != mypid: + print("This program was already running.") + Debug.out("I am a duplicate. I shall end myself. ({0})".format(" ".join(line))) + exit(0) + + @staticmethod + def checkForProcess(proc, Debug): + output = [] + + for line in Popen(proc, shell=True, stdout=PIPE).stdout: + fields = line.split() + if not fields[0].isdigit(): + continue + + output.append(fields) + + return output + +class DebugMe(): + def __init__(self, toggle): + if toggle: + self.output = True + else: + self.output = False + + def out(self, msg): + if not self.output: + return + + print(">> {0}".format(msg)) + +if __name__ == "__main__": + parser = OptionParser() + parser.add_option( + '-a', + '--action', + dest = 'action', + default = None, + type = 'choice', + choices = ['playPause', 'play', 'pause', 'next', 'previous'], + help = 'Music player actions (playPause/play/pause/next/previous).' + ) + parser.add_option( + '-n', + '--skip_notify', + dest = 'skipNotify', + action = 'store_true', + default = False, + help = 'Song change notifications will be turned off.' + ) + parser.add_option( + '-d', + '--debug', + dest = 'debug', + action = 'store_true', + default = False, + help = 'Debug messages will be displayed.' + ) + + (options, args) = parser.parse_args() + + Debug = DebugMe(options.debug) + print("Spotify-notify v0.6") + + if SPOTIFY_PROCESS_NAME: + SpotifyNotify.spotifyPath = SPOTIFY_PROCESS_NAME + else: + print "Spotify is not running" + sys.exit(0) + + SN = SpotifyNotify(Debug) + + if options.action: + action = options.action + action = action[0:1].upper() + action[1:] + SN.executeCommand(action) + + SpotifyNotify.preventDuplicate(Debug) + + try: + indicateserver = indicate.indicate_server_ref_default() + indicateserver.set_type("music.spotify") + indicateserver.set_desktop_file("/usr/share/applications/spotify.desktop") + indicateserver.show() + except: + pass + SN.pollChange() + print "Done" + diff --git a/spotify-remote.sh b/spotify-remote.sh new file mode 100755 index 0000000..49d760e --- /dev/null +++ b/spotify-remote.sh @@ -0,0 +1,114 @@ +#!/bin/bash +# Extracted from: http://ubuntuforums.org/showthread.php?t=1797848 +# User: azzid +# Modified by Balkian +# Collect DBUS_SESSION_BUS_ADDRESS from running process +function set_dbus_adress +{ + USER=$1 + PROCESS=$2 + PID=`pgrep -o -u $USER $PROCESS` + ENVIRON=/proc/$PID/environ + + if [ -e $ENVIRON ] + then + export `grep -z DBUS_SESSION_BUS_ADDRESS $ENVIRON` + else + echo "Unable to set DBUS_SESSION_BUS_ADDRESS." + exit 1 + fi +} + +function spotify_cmd +{ + dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.$1 1> /dev/null +} + +function spotify_query +{ + qdbus org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Get org.mpris.MediaPlayer2.Player PlaybackStatus +} + +function spotify_metadata +{ + qdbus com.spotify.qt / org.freedesktop.MediaPlayer2.GetMetadata +} + +function spotify_notify +{ + metadata=`spotify_metadata` + echo "Metadata: $metadata" + title=`echo "$metadata" | grep title | cut -d' ' -f2-` + artist=`echo "$metadata" | grep artist | cut -d' ' -f2-` + image=`echo "$metadata" | grep artUrl | cut -d' ' -f3` + wget $image -O /tmp/image + echo "notifying $title" + notify-send "$artist" "$title" --icon=/tmp/image +} + +function quit_message +{ + echo "Usage: `basename $0` {play|pause|playpause|next|previous|stop|playstatus|}" + exit 1 +} + +# Count arguments, must be 1 +if [ "$#" -ne "1" ] +then + echo -e "You must supply exactly one argument!\n" + quit_message +fi + +# Check if DBUS_SESSION is set +if [ -z $DBUS_SESSION_BUS_ADDRESS ] + then + #echo "DBUS_SESSION_BUS_ADDRESS not set. Guessing." + set_dbus_adress `whoami` spotify +fi + +case "$1" in + play) + spotify_cmd Play + spotify_notify + ;; + pause) + spotify_cmd Pause + spotify_notify + ;; + playpause) + spotify_cmd PlayPause + spotify_notify + ;; + next) + spotify_cmd Next + spotify_notify + ;; + previous) + spotify_cmd Previous + spotify_notify + ;; + stop) + spotify_cmd Stop + spotify_notify + ;; + spotify:user:*) + spotify_cmd "OpenUri string:$1" + spotify_cmd Play + spotify_notify + ;; + spotify:*:*) + spotify_cmd "OpenUri string:$1" + ;; + playstatus) + spotify_query + ;; + metadata) + spotify_metadata; + ;; + *) + echo -e "Bad argument.\n" + quit_message + ;; +esac + +exit 0