#!/usr/bin/python from SimpleWebSocketServer import SimpleWebSocketServer, WebSocket import json import socket import os import threading import select import random import SimpleHTTPServer import SocketServer SOCKPATH='/home/dario/.mpv.sock' global mpvParser mpvParser = None class SocketPoller(threading.Thread): def __init__(self, sockParser): super(SocketPoller, self).__init__() self.sockParser = sockParser self.stop=False if not os.path.exists(SOCKPATH): raise Exception("Could not find server socket ~/.mpv.sock, exiting") self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) self.sock.connect(SOCKPATH) self.buf="" def run(self): while not self.stop: if len( select.select([self.sock], [], [])[0] ) > 0: self.buf += self.sock.recv(1) if '\n' in self.buf: self.sockParser.newData(self.buf) self.buf="" def sendData(self, data): print "sending data '%s'"%data if not '\n' in data: data+='\n' self.sock.sendall(data) class MpvSockParser(object): def __init__(self): self.listeners = [] self.playerState = { "totalDuration": 42.0, "currentDuration": 23.0, "volume": 66, "fileName": "No Data Yet", "isPlaying": False } self.poller = None self.waitingForCommand = None def registerListener(self, listener): self.listeners.append(listener) def unregisterListener(self, listener): self.listeners.remove(listener) def notifyListeners(self): for l in self.listeners: l.dataNotify(self.playerState) def startPoll(self): self.poller = SocketPoller(self) self.poller.sendData('{"command":["observe_property",1,"time-pos"]}') self.poller.sendData('{"command":["observe_property",2,"volume"]}') self.poller.sendData('{"command":["observe_property",3,"filename"]}') self.poller.sendData('{"command":["observe_property",4,"duration"]}') self.poller.sendData('{"command":["observe_property",5,"mute"]}') self.poller.sendData('{"command":["get_property","pause"],"request_id":10}') self.poller.sendData('{"command":["get_property","mute"],"request_id":11}') self.poller.daemon = True self.poller.start() def newData(self, data): data = json.loads(data) # mpv-generated event if "event" in data: self.processEvent(data) # answer to our request if 'error' in data: self.processCommand(data) def processEvent(self, data): sendNotify = True if "data" in data and data["data"]==None: return if data['event'] == 'property-change' and data['name'] == 'time-pos': oldCur = self.playerState['currentDuration'] curCur = int(data['data']) if curCur - oldCur < 1: sendNotify = False self.playerState['currentDuration'] = curCur if data['event'] == 'property-change' and data['name'] == 'volume': self.playerState['volume'] = int(data['data']) if data['event'] == 'property-change' and data['name'] == 'mute': self.playerState['isMuted'] = data['data'] if data['event'] == 'property-change' and data['name'] == 'filename': self.playerState['fileName'] = data['data'] if data['event'] == 'property-change' and data['name'] == 'duration': self.playerState['totalDuration'] = int(data['data']) if data['event'] == 'pause': self.playerState['isPlaying'] = False if data['event'] == 'unpause': self.playerState['isPlaying'] = True if sendNotify: print self.playerState self.notifyListeners() def processCommand(self, data): if "request_id" in data and data['request_id'] == 10: self.playerState['isPlaying'] = not data["data"] if "request_id" in data and data['request_id'] == 11: self.playerState['isMuted'] = data["data"] def sendCommand(self, command): if command["command"] == "play": self.poller.sendData('{ "command": ["set_property", "pause", false] }') if command["command"] == "pause": self.poller.sendData('{ "command": ["set_property", "pause", true] }') if command["command"] == "mute": self.poller.sendData('{ "command": ["set_property", "mute", true] }') if command["command"] == "unmute": self.poller.sendData('{ "command": ["set_property", "mute", false] }') if command["command"] == "seek": self.poller.sendData('{ "command": ["seek", "%s", "absolute"] }'%command['seekValue']) if command["command"] == "volume": self.poller.sendData('{ "command": ["set", "volume", "%s"] }'%command['volume']) if command["command"] == "seekChapter": if command['direction'] == 'forward': direction = +1 elif command['direction'] == 'backward': direction = -1 self.poller.sendData('{ "command": ["add", "chapter", %s] }'%direction) class WSHandler(WebSocket): def handleMessage(self): global mpvParser command = json.loads(self.data) print 'got command %s'%command mpvParser.sendCommand(command) def handleConnected(self): global mpvParser mpvParser.registerListener(self) print self.address, 'connected' def handleClose(self): global mpvParser print self.address, 'closed' mpvParser.unregisterListener(self) def dataNotify(self, data): data['type'] = 'status' self.sendMessage(unicode( json.dumps(data) )) if __name__=='__main__': global mpvParser mpvParser = MpvSockParser() mpvParser.startPoll() os.chdir('../client/') SocketServer.TCPServer.allow_reuse_address = True httpd = SocketServer.TCPServer(("", 8001), SimpleHTTPServer.SimpleHTTPRequestHandler) wsd = SimpleWebSocketServer('', 8000, WSHandler) wsThread = threading.Thread(target=wsd.serveforever) wsThread.daemon=True wsThread.start() httpd.serve_forever()