Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
robstar committed May 16, 2010
0 parents commit 8067c67
Show file tree
Hide file tree
Showing 6 changed files with 402 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
@@ -0,0 +1,2 @@
*.pyc
*~
Empty file added README
Empty file.
113 changes: 113 additions & 0 deletions __init__.py
@@ -0,0 +1,113 @@
#!/usr/bin/env python
# Copyright (C) 2010 robstar.cc <info at navarin dot de>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.


try:
import os
import sys
import subprocess
import rb
import gobject
import gtk, gtk.glade
import gconf, gnome
except ImportError as e:
print "Depencies missing:"
print str(e)


class RhythmotePlugin (rb.Plugin):
'''Rhythmote's main class.'''

def __init__(self):
rb.Plugin.__init__(self)
path = os.path.abspath( __file__ )

self.daemon = None
self.cwd = path[:path.rfind("/")]
self.gconf_keys = {
'port' : '/apps/rhythmbox/plugins/rhythmote/port'
}
self.client = gconf.client_get_default()
self.port = self.client.get_string(self.gconf_keys["port"]) or "8484"



def activate(self, shell):
'''Default actication method, automatically called when the plugin is
started from within Rhythmbox. It starts a separated process which acts
as a daemon and listens to the port, entered in the settings dialog.'''

print "starting Rhythmote"
self.restart()
#self.daemon = subprocess.Popen(["/usr/bin/python", self.cwd+"/daemon.py", str(self.port)]);


def deactivate(self, shell):
'''This method is called automatically, when Ryhthmbox is closed or the
plugin is deactivated by the user. It cleans up all objects which are
not needed anymore and sends a SIGTERM to stop the daemon.'''

print "quitting Rhythmote"

if self.daemon:
self.daemon.terminate()


def create_configure_dialog(self, dialog=None):
'''creates the configuration dialog using a libglade gui'''

if dialog == None:

self.configure_callback_dic = {
"rb_rhythmote_port_changed" : lambda w: self.client.set_string(self.gconf_keys['port'], self.port)
}

gladexml = gtk.glade.XML(self.find_file("rhythmote-prefs.glade"))
gladexml.signal_autoconnect(self.configure_callback_dic)
gladexml.get_widget("port").set_text(self.port)

dialog = gladexml.get_widget('preferences_dialog')
def dialog_response (dialog, response):
port = gladexml.get_widget("port").get_text()
try:
number = int(port)
except (ValueError, IndexError):
dialog.hide()

#if port == self.port:
# dialog.hide()

self.port = port
self.client.set_string(self.gconf_keys['port'], self.port)
self.restart()
print "Rhythmote now running on port: "+ port
dialog.hide()

dialog.connect("response", dialog_response)

dialog.present()
return dialog


def restart(self):
if self.daemon:
print "terminating daemon"
self.daemon.terminate()
self.daemon = subprocess.Popen(["/usr/bin/python", self.cwd+"/daemon.py", str(self.port)]);



192 changes: 192 additions & 0 deletions daemon.py
@@ -0,0 +1,192 @@


#Copyright (C) 2009 Nikitas Stamatopoulos

#This program is free software: you can redistribute it and/or modify
#it under the terms of the GNU General Public License as published by
#the Free Software Foundation, either version 3 of the License, or
#(at your option) any later version.

#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#GNU General Public License for more details.

#You should have received a copy of the GNU General Public License
#along with this program. If not, see <http://www.gnu.org/licenses/>.



import dbus, re, os, SocketServer, socket,sys
import signal

if len(sys.argv) == 2:
port = int(sys.argv[1])
else:
port = 8484

def on_exit(sig, func=None):
print "exiting Rhythmote daemon"
server_socket.shutdown(1)
server_socket.close()

signal.signal(signal.SIGTERM, on_exit)




bus = dbus.SessionBus()
rbox = bus.get_object( 'org.gnome.Rhythmbox', '/org/gnome/Rhythmbox/Player')
rboxs = bus.get_object( 'org.gnome.Rhythmbox', '/org/gnome/Rhythmbox/Shell')
rboxp = bus.get_object( 'org.gnome.Rhythmbox', '/org/gnome/Rhythmbox/PlaylistManager')
player = dbus.Interface(rbox, 'org.gnome.Rhythmbox.Player')
shell = dbus.Interface(rboxs, 'org.gnome.Rhythmbox.Shell')
playlist = dbus.Interface(rboxp, 'org.gnome.Rhythmbox.PlaylistManager')

volume = 0
home = os.environ['HOME']
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.settimeout(None)
server_socket.bind(("", port))
server_socket.listen(5)
test_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
test_socket.connect(('google.de',0))
ip = test_socket.getsockname()[0]
test_socket.close()
client_socket = None
print 'Started Rhythmote on port %s' % (port)
print 'Your IP is %s' % (ip)
while 1:
client_socket, address = server_socket.accept()
received = client_socket.recv(512)
action, var = received.split('/')

if action == "coverImage":
try:
cover = open(shell.getSongProperties(player.getPlayingUri())['rb:coverArt-uri'] )
reply=cover.read()
cover.close()
except IOError:
reply=""

client_socket.send(reply)

if action == "coverExists":
if shell.getSongProperties(player.getPlayingUri()).has_key('rb:coverArt-uri'):
coverExists="true"
artwork_path = shell.getSongProperties(player.getPlayingUri())['rb:coverArt-uri']
if os.path.isfile(artwork_path):
size = int(os.path.getsize(artwork_path))
if size > 200000:
coverExists="false"
else:
coverExists="false"
client_socket.send(reply)

if action == "playPause":
player.playPause(1)

if action == "next":
player.next()

if action == "prev":
player.previous()

if action == "volumeDown":
currVol = player.getVolume()
currVol = currVol-0.1
if currVol < 0:
currVol=0
player.setVolume(currVol)

if action == "volumeUp":
player.setVolume(player.getVolume()+0.1)

if action == "mute":
if player.getMute() == True:
player.setMute(False)
else:
player.setMute(True)

if action == "status":
if player.getPlaying():
reply = "playing"
else:
reply = "paused"
client_socket.send(reply.encode('utf-8'))

if action == "album":
reply = str(shell.getSongProperties(player.getPlayingUri())["album"])
client_socket.send(reply.encode('utf-8'))

if action == "artist":
reply = str(shell.getSongProperties(player.getPlayingUri())["artist"])
client_socket.send(reply.encode('utf-8'))

if action == "title":
reply = str(shell.getSongProperties(player.getPlayingUri())["title"])
client_socket.send(reply.encode('utf-8'))

if action == "trackCurrentTime":
reply = str(int(player.getElapsed()))
client_socket.send(reply)

if action == "trackTotalTime":
reply = str(int(shell.getSongProperties(player.getPlayingUri())['duration']))
client_socket.send(reply)

if action == "seek":
player.setElapsed(int(var))

if action == "shuffle":
pass

if action == "repeat":
pass


if action == "all":
try:
if player.getPlaying():
status = "playing"
else:
status = "paused"
album = str(shell.getSongProperties(player.getPlayingUri())["album"])
artist = str(shell.getSongProperties(player.getPlayingUri())["artist"])
title = str(shell.getSongProperties(player.getPlayingUri())["title"])
trackCurrentTime = str(int(player.getElapsed()))
trackTotalTime = str(int(shell.getSongProperties(player.getPlayingUri())['duration']))
coverExists="false"
if shell.getSongProperties(player.getPlayingUri()).has_key('rb:coverArt-uri'):
coverExists="true"
artwork_path = shell.getSongProperties(player.getPlayingUri())['rb:coverArt-uri']
if os.path.isfile(artwork_path):
size = int(os.path.getsize(artwork_path))
if size > 200000:
coverExists="false"
else:
coverExists="false"
sep = '/'
reply=status+sep+album+sep+artist+sep+title+sep+trackCurrentTime+sep+trackTotalTime+sep+coverExists
client_socket.send(reply.encode('utf-8'))

except Exception as e:
lala=1

client_socket.close()


### DEBUG ###
# code to get all methods
#from dbus import SessionBus, Interface
#from dbus._expat_introspect_parser import process_introspection_data

def introspect_object(named_service, object_path):
'''This is debug output function'''
obj = SessionBus().get_object(named_service, object_path)
iface = Interface(obj, 'org.freedesktop.DBus.Introspectable')
return process_introspection_data(iface.Introspect())

#introspect_object('org.gnome.Rhythmbox', '/org/gnome/Rhythmbox/Shell')


86 changes: 86 additions & 0 deletions rhythmote-prefs.glade
@@ -0,0 +1,86 @@
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">

<glade-interface>
<requires lib="gnome"/>
<widget class="GtkDialog" id="preferences_dialog">
<property name="visible">True</property>
<property name="title" translatable="yes">Rhythmote Preferences</property>
<property name="type">GTK_WINDOW_TOPLEVEL</property>
<property name="window_position">GTK_WIN_POS_NONE</property>
<property name="modal">False</property>
<property name="resizable">True</property>
<property name="destroy_with_parent">False</property>
<property name="decorated">True</property>
<property name="skip_taskbar_hint">False</property>
<property name="skip_pager_hint">False</property>
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
<property name="focus_on_map">True</property>
<property name="urgency_hint">False</property>
<property name="has_separator">True</property>
<child internal-child="vbox">
<widget class="GtkVBox" id="dialog-vbox2">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child>
<widget class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<child>
<widget class="GtkLabel" id="port">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="yalign">1</property>
<property name="label" translatable="yes">Port:</property>
</widget>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="port">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
<property name="text" translatable="yes">8484</property>
<property name="caps_lock_warning">False</property>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
<child internal-child="action_area">
<widget class="GtkHButtonBox" id="dialog-action_area2">
<property name="visible">True</property>
<property name="layout_style">end</property>
<child>
<widget class="GtkButton" id="button1">
<property name="label" translatable="yes">close</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
</widget>
</child>
</widget>
</glade-interface>

0 comments on commit 8067c67

Please sign in to comment.