You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
290 lines
9.1 KiB
290 lines
9.1 KiB
#!/usr/bin/env python
|
|
############################################################################
|
|
# WebControl script for Amarok
|
|
# (c) 2005 Jonas Drewsen <kde@xspect.dk>
|
|
# (c) 2006 Peter C. Ndikuwera <pndiku@gmail.com>
|
|
#
|
|
# Depends on: Python 2.2, PyQt
|
|
#
|
|
############################################################################
|
|
# Based on
|
|
# Python-Qt template script for Amarok
|
|
# (c) 2005 Mark Kretschmann <markey@web.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 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
############################################################################
|
|
|
|
import ConfigParser
|
|
import os
|
|
import sys
|
|
import socket
|
|
import signal
|
|
import threading
|
|
from time import sleep
|
|
|
|
import Globals
|
|
from Playlist import Playlist
|
|
import RequestHandler
|
|
import BaseHTTPServer
|
|
from WebPublisher import *
|
|
|
|
import time
|
|
|
|
# necessary for <= python2.2 that cannot handle "infds" in var
|
|
import string
|
|
|
|
try:
|
|
from qt import *
|
|
except:
|
|
os.popen( "kdialog --sorry 'PyQt (Qt bindings for Python) is required for this script.'" )
|
|
raise
|
|
|
|
|
|
# Replace with real name
|
|
debug_prefix = "[WebControl Script]"
|
|
|
|
|
|
class ConfigDialog( QDialog ):
|
|
""" Configuration widget """
|
|
|
|
def __init__( self ):
|
|
QDialog.__init__( self )
|
|
self.setWFlags( Qt.WDestructiveClose )
|
|
self.setCaption( "WebControl - Amarok" )
|
|
|
|
self.config = ConfigParser.ConfigParser()
|
|
|
|
allowControl = RequestHandler.AmarokStatus.allowControl
|
|
publish = RequestHandler.AmarokStatus.publish
|
|
try:
|
|
config = ConfigParser.ConfigParser()
|
|
config.read( "webcontrolrc" )
|
|
allowControl = string.find(config.get( "General", "allowcontrol" ), "True") >= 0
|
|
publish = string.find(config.get( "General", "publish" ), "True") >= 0
|
|
except:
|
|
pass
|
|
|
|
self.lay = QHBoxLayout( self )
|
|
|
|
self.vbox = QVBox( self )
|
|
self.lay.addWidget( self.vbox )
|
|
|
|
self.hbox1 = QHBox( self.vbox )
|
|
|
|
self.allowControl = QCheckBox( QString("Allow control"), self.hbox1 )
|
|
self.allowControl.setChecked(allowControl)
|
|
|
|
self.hbox1 = QHBox( self.vbox )
|
|
|
|
self.publish = QCheckBox( QString("Publish"), self.hbox1 )
|
|
self.publish.setChecked(publish)
|
|
|
|
self.hbox = QHBox( self.vbox )
|
|
|
|
self.ok = QPushButton( self.hbox )
|
|
self.ok.setText( "Ok" )
|
|
|
|
self.cancel = QPushButton( self.hbox )
|
|
self.cancel.setText( "Cancel" )
|
|
self.cancel.setDefault( True )
|
|
|
|
self.connect( self.ok, SIGNAL( "clicked()" ), self.save )
|
|
self.connect( self.cancel, SIGNAL( "clicked()" ), self, SLOT( "reject()" ) )
|
|
|
|
self.adjustSize()
|
|
|
|
def save( self ):
|
|
""" Saves configuration to file """
|
|
|
|
self.file = file( "webcontrolrc", 'w' )
|
|
|
|
self.config = ConfigParser.ConfigParser()
|
|
self.config.add_section( "General" )
|
|
self.config.set( "General", "allowcontrol", self.allowControl.isChecked() )
|
|
self.config.set( "General", "publish", self.publish.isChecked() )
|
|
self.config.write( self.file )
|
|
self.file.close()
|
|
debug( "Saved config" )
|
|
self.accept()
|
|
|
|
|
|
class Notification( QCustomEvent ):
|
|
__super_init = QCustomEvent.__init__
|
|
def __init__( self, str ):
|
|
self.__super_init(QCustomEvent.User + 1)
|
|
self.string = str
|
|
|
|
class WebControl( QApplication ):
|
|
""" The main application, also sets up the Qt event loop """
|
|
|
|
def __init__( self, args ):
|
|
QApplication.__init__( self, args )
|
|
debug( "Started." )
|
|
|
|
self.readSettings()
|
|
|
|
self.t = threading.Thread( target = self.readStdin )
|
|
self.t.start()
|
|
|
|
RequestHandler.PLIST = Playlist()
|
|
|
|
p_incr = 0
|
|
|
|
while p_incr < 10:
|
|
try:
|
|
p_i=p_incr+Globals.PORT
|
|
self.srv = BaseHTTPServer.HTTPServer(('',p_i),RequestHandler.RequestHandler)
|
|
publisher.port = p_i
|
|
break
|
|
except socket.error:
|
|
p_incr+=1
|
|
|
|
self.zeroconfPublishing()
|
|
self.snsrv = QSocketNotifier(self.srv.fileno(), QSocketNotifier.Read)
|
|
self.snsrv.connect( self.snsrv, SIGNAL('activated(int)'), self.readSocket )
|
|
|
|
def readSocket( self ):
|
|
# Got a read event on the HTTP server socket.
|
|
self.srv.handle_request()
|
|
|
|
def readSettings( self ):
|
|
""" Reads settings from configuration file """
|
|
config = ConfigParser.ConfigParser()
|
|
config.read( "webcontrolrc" )
|
|
|
|
try:
|
|
RequestHandler.AmarokStatus.allowControl = string.find(config.get( "General", "allowcontrol" ), "True") >= 0
|
|
RequestHandler.AmarokStatus.publish = string.find(config.get( "General", "publish" ), "True") >= 0
|
|
except:
|
|
debug( "No config file found, using defaults." )
|
|
|
|
|
|
def postConfigure( self ):
|
|
self.readSettings()
|
|
self.zeroconfPublishing()
|
|
|
|
def zeroconfPublishing( self ):
|
|
if RequestHandler.AmarokStatus.publish:
|
|
if not publisher.active:
|
|
threading.Thread(target = publisher.run).start()
|
|
else:
|
|
publisher.shutdown()
|
|
|
|
############################################################################
|
|
# Stdin-Reader Thread
|
|
############################################################################
|
|
|
|
def readStdin( self ):
|
|
while True:
|
|
line = sys.stdin.readline()
|
|
if line:
|
|
tqApp.postEvent( self, Notification(line) )
|
|
else:
|
|
break
|
|
|
|
############################################################################
|
|
# Notification Handling
|
|
############################################################################
|
|
|
|
def customEvent( self, notification ):
|
|
""" Handles the notifications """
|
|
|
|
string = QString(notification.string)
|
|
debug( "Received notification: " + str( string ) )
|
|
|
|
if string.contains( "configure" ):
|
|
self.configure()
|
|
|
|
elif string.contains( "exit" ):
|
|
cleanup(None,None)
|
|
|
|
elif string.contains( "engineStateChange: play" ):
|
|
self.engineStatePlay()
|
|
|
|
elif string.contains( "engineStateChange: idle" ):
|
|
self.engineStateIdle()
|
|
|
|
elif string.contains( "engineStateChange: pause" ):
|
|
self.engineStatePause()
|
|
|
|
elif string.contains( "engineStateChange: empty" ):
|
|
self.engineStatePause()
|
|
|
|
elif string.contains( "trackChange" ):
|
|
self.trackChange()
|
|
|
|
else:
|
|
debug( "Unknown notification: " + str(string) + " -> ignoring")
|
|
|
|
# Notification callbacks. Implement these functions to react to specific notification
|
|
# events from Amarok:
|
|
|
|
def configure( self ):
|
|
debug( "configuration" )
|
|
|
|
self.dia = ConfigDialog()
|
|
self.dia.show()
|
|
self.connect( self.dia, SIGNAL( "destroyed()" ), self.postConfigure )
|
|
|
|
def engineStatePlay( self ):
|
|
""" Called when Engine state changes to Play """
|
|
RequestHandler.AmarokStatus.dcop_trackcurrenttime = Globals.PlayerDcop("trackCurrentTime")
|
|
RequestHandler.AmarokStatus.dcop_trackcurrenttime.result()
|
|
RequestHandler.AmarokStatus.dcop_tracktotaltime = Globals.PlayerDcop("trackTotalTime")
|
|
RequestHandler.AmarokStatus.dcop_tracktotaltime.result()
|
|
RequestHandler.AmarokStatus.playState = RequestHandler.AmarokStatus.EnginePlay
|
|
|
|
def engineStateIdle( self ):
|
|
""" Called when Engine state changes to Idle """
|
|
RequestHandler.AmarokStatus.playState = RequestHandler.AmarokStatus.EngineIdle
|
|
|
|
def engineStatePause( self ):
|
|
""" Called when Engine state changes to Pause """
|
|
RequestHandler.AmarokStatus.playState = RequestHandler.AmarokStatus.EnginePause
|
|
|
|
def engineStateEmpty( self ):
|
|
""" Called when Engine state changes to Empty """
|
|
RequestHandler.AmarokStatus.playState = RequestHandler.AmarokStatus.EngineEmpty
|
|
|
|
def trackChange( self ):
|
|
""" Called when a new track starts """
|
|
RequestHandler.AmarokStatus.dcop_trackcurrentindex = Globals.PlaylistDcop("getActiveIndex")
|
|
RequestHandler.AmarokStatus.dcop_trackcurrentindex.result()
|
|
RequestHandler.AmarokStatus.dcop_trackcurrenttime = Globals.PlayerDcop("trackCurrentTime")
|
|
RequestHandler.AmarokStatus.dcop_trackcurrenttime.result()
|
|
RequestHandler.AmarokStatus.dcop_tracktotaltime = Globals.PlayerDcop("trackTotalTime")
|
|
RequestHandler.AmarokStatus.dcop_tracktotaltime.result()
|
|
|
|
|
|
|
|
|
|
############################################################################
|
|
|
|
def debug( message ):
|
|
""" Prints debug message to stdout """
|
|
|
|
print debug_prefix + " " + message
|
|
|
|
def cleanup(sig,frame):
|
|
publisher.shutdown()
|
|
os._exit(0)
|
|
|
|
|
|
def guithread():
|
|
app = WebControl( sys.argv )
|
|
app.exec_loop()
|
|
|
|
if __name__ == "__main__":
|
|
Globals.EXEC_PATH = os.path.abspath(sys.path[0])
|
|
gui = threading.Thread(target=guithread)
|
|
gui.start()
|
|
signal.signal(signal.SIGTERM,cleanup)
|
|
# just wait quietly for the end
|
|
while 1: sleep(120)
|