Add alertOSDSupport setting to MPC-**

This commit is contained in:
Etoh 2017-12-28 15:33:25 +00:00
parent 4a467faff0
commit df163cd8a1

View File

@ -7,7 +7,7 @@ from functools import wraps
from syncplay.players.basePlayer import BasePlayer from syncplay.players.basePlayer import BasePlayer
import re import re
from syncplay.utils import retry from syncplay.utils import retry
from syncplay import constants from syncplay import constants
from syncplay.messages import getMessage from syncplay.messages import getMessage
import os.path import os.path
@ -29,7 +29,7 @@ class MpcHcApi:
self.__listener.setDaemon(True) self.__listener.setDaemon(True)
self.__listener.start() self.__listener.start()
self.__locks.listenerStart.wait() self.__locks.listenerStart.wait()
def waitForFileStateReady(f): #@NoSelf def waitForFileStateReady(f): #@NoSelf
@wraps(f) @wraps(f)
def wrapper(self, *args, **kwds): def wrapper(self, *args, **kwds):
@ -37,35 +37,35 @@ class MpcHcApi:
raise self.PlayerNotReadyException() raise self.PlayerNotReadyException()
return f(self, *args, **kwds) return f(self, *args, **kwds)
return wrapper return wrapper
def startMpc(self, path, args=()): def startMpc(self, path, args=()):
args = "%s /slave %s" % (" ".join(args), str(self.__listener.hwnd)) args = "%s /slave %s" % (" ".join(args), str(self.__listener.hwnd))
win32api.ShellExecute(0, "open", path, args, None, 1) win32api.ShellExecute(0, "open", path, args, None, 1)
if not self.__locks.mpcStart.wait(constants.MPC_OPEN_MAX_WAIT_TIME): if not self.__locks.mpcStart.wait(constants.MPC_OPEN_MAX_WAIT_TIME):
raise self.NoSlaveDetectedException(getMessage("mpc-slave-error")) raise self.NoSlaveDetectedException(getMessage("mpc-slave-error"))
self.__mpcExistenceChecking.start() self.__mpcExistenceChecking.start()
def openFile(self, filePath): def openFile(self, filePath):
self.__listener.SendCommand(self.CMD_OPENFILE, filePath) self.__listener.SendCommand(self.CMD_OPENFILE, filePath)
def isPaused(self): def isPaused(self):
return self.playState <> self.__MPC_PLAYSTATE.PS_PLAY and self.playState <> None return self.playState <> self.__MPC_PLAYSTATE.PS_PLAY and self.playState <> None
def askForVersion(self): def askForVersion(self):
self.__listener.SendCommand(self.CMD_GETVERSION) self.__listener.SendCommand(self.CMD_GETVERSION)
@waitForFileStateReady @waitForFileStateReady
def pause(self): def pause(self):
self.__listener.SendCommand(self.CMD_PAUSE) self.__listener.SendCommand(self.CMD_PAUSE)
@waitForFileStateReady @waitForFileStateReady
def playPause(self): def playPause(self):
self.__listener.SendCommand(self.CMD_PLAYPAUSE) self.__listener.SendCommand(self.CMD_PLAYPAUSE)
@waitForFileStateReady @waitForFileStateReady
def unpause(self): def unpause(self):
self.__listener.SendCommand(self.CMD_PLAY) self.__listener.SendCommand(self.CMD_PLAY)
@waitForFileStateReady @waitForFileStateReady
def askForCurrentPosition(self): def askForCurrentPosition(self):
self.__listener.SendCommand(self.CMD_GETCURRENTPOSITION) self.__listener.SendCommand(self.CMD_GETCURRENTPOSITION)
@ -84,13 +84,13 @@ class MpcHcApi:
('nMsgPos', ctypes.c_int32), ('nMsgPos', ctypes.c_int32),
('nDurationMS', ctypes.c_int32), ('nDurationMS', ctypes.c_int32),
('strMsg', ctypes.c_wchar * (len(message) + 1)) ('strMsg', ctypes.c_wchar * (len(message) + 1))
] ]
cmessage = __OSDDATASTRUCT() cmessage = __OSDDATASTRUCT()
cmessage.nMsgPos = MsgPos cmessage.nMsgPos = MsgPos
cmessage.nDurationMS = DurationMs cmessage.nDurationMS = DurationMs
cmessage.strMsg = message cmessage.strMsg = message
self.__listener.SendCommand(self.CMD_OSDSHOWMESSAGE, cmessage) self.__listener.SendCommand(self.CMD_OSDSHOWMESSAGE, cmessage)
def sendRawCommand(self, cmd, value): def sendRawCommand(self, cmd, value):
self.__listener.SendCommand(cmd, value) self.__listener.SendCommand(cmd, value)
@ -100,7 +100,7 @@ class MpcHcApi:
self.__locks.mpcStart.set() self.__locks.mpcStart.set()
if self.callbacks.onConnected: if self.callbacks.onConnected:
thread.start_new_thread(self.callbacks.onConnected, ()) thread.start_new_thread(self.callbacks.onConnected, ())
elif cmd == self.CMD_STATE: elif cmd == self.CMD_STATE:
self.loadState = int(value) self.loadState = int(value)
fileNotReady = self.loadState == self.__MPC_LOADSTATE.MLS_CLOSING or self.loadState == self.__MPC_LOADSTATE.MLS_LOADING or self.loadState == self.__MPC_LOADSTATE.MLS_CLOSED fileNotReady = self.loadState == self.__MPC_LOADSTATE.MLS_CLOSING or self.loadState == self.__MPC_LOADSTATE.MLS_LOADING or self.loadState == self.__MPC_LOADSTATE.MLS_CLOSED
@ -111,12 +111,12 @@ class MpcHcApi:
self.__locks.fileReady.set() self.__locks.fileReady.set()
if self.callbacks.onFileStateChange: if self.callbacks.onFileStateChange:
thread.start_new_thread(self.callbacks.onFileStateChange, (self.loadState,)) thread.start_new_thread(self.callbacks.onFileStateChange, (self.loadState,))
elif cmd == self.CMD_PLAYMODE: elif cmd == self.CMD_PLAYMODE:
self.playState = int(value) self.playState = int(value)
if self.callbacks.onUpdatePlaystate: if self.callbacks.onUpdatePlaystate:
thread.start_new_thread(self.callbacks.onUpdatePlaystate, (self.playState,)) thread.start_new_thread(self.callbacks.onUpdatePlaystate, (self.playState,))
elif cmd == self.CMD_NOWPLAYING: elif cmd == self.CMD_NOWPLAYING:
value = re.split(r'(?<!\\)\|', value) value = re.split(r'(?<!\\)\|', value)
if self.filePath == value[3]: if self.filePath == value[3]:
@ -130,30 +130,30 @@ class MpcHcApi:
thread.start_new_thread(self.callbacks.onUpdateFilename, (self.filePlaying,)) thread.start_new_thread(self.callbacks.onUpdateFilename, (self.filePlaying,))
if self.callbacks.onUpdateFileDuration: if self.callbacks.onUpdateFileDuration:
thread.start_new_thread(self.callbacks.onUpdateFileDuration, (self.fileDuration,)) thread.start_new_thread(self.callbacks.onUpdateFileDuration, (self.fileDuration,))
elif cmd == self.CMD_CURRENTPOSITION: elif cmd == self.CMD_CURRENTPOSITION:
self.lastFilePosition = float(value) self.lastFilePosition = float(value)
if self.callbacks.onGetCurrentPosition: if self.callbacks.onGetCurrentPosition:
thread.start_new_thread(self.callbacks.onGetCurrentPosition, (self.lastFilePosition,)) thread.start_new_thread(self.callbacks.onGetCurrentPosition, (self.lastFilePosition,))
elif cmd == self.CMD_NOTIFYSEEK: elif cmd == self.CMD_NOTIFYSEEK:
if self.lastFilePosition <> float(value): #Notify seek is sometimes sent twice if self.lastFilePosition <> float(value): #Notify seek is sometimes sent twice
self.lastFilePosition = float(value) self.lastFilePosition = float(value)
if self.callbacks.onSeek: if self.callbacks.onSeek:
thread.start_new_thread(self.callbacks.onSeek, (self.lastFilePosition,)) thread.start_new_thread(self.callbacks.onSeek, (self.lastFilePosition,))
elif cmd == self.CMD_DISCONNECT: elif cmd == self.CMD_DISCONNECT:
if self.callbacks.onMpcClosed: if self.callbacks.onMpcClosed:
thread.start_new_thread(self.callbacks.onMpcClosed, (None,)) thread.start_new_thread(self.callbacks.onMpcClosed, (None,))
elif cmd == self.CMD_VERSION: elif cmd == self.CMD_VERSION:
if self.callbacks.onVersion: if self.callbacks.onVersion:
self.version = value self.version = value
thread.start_new_thread(self.callbacks.onVersion, (value,)) thread.start_new_thread(self.callbacks.onVersion, (value,))
class PlayerNotReadyException(Exception): class PlayerNotReadyException(Exception):
pass pass
class __Callbacks: class __Callbacks:
def __init__(self): def __init__(self):
self.onConnected = None self.onConnected = None
@ -166,13 +166,13 @@ class MpcHcApi:
self.onFileStateChange = None self.onFileStateChange = None
self.onMpcClosed = None self.onMpcClosed = None
self.onVersion = None self.onVersion = None
class __Locks: class __Locks:
def __init__(self): def __init__(self):
self.listenerStart = threading.Event() self.listenerStart = threading.Event()
self.mpcStart = threading.Event() self.mpcStart = threading.Event()
self.fileReady = threading.Event() self.fileReady = threading.Event()
def __mpcReadyInSlaveMode(self): def __mpcReadyInSlaveMode(self):
while True: while True:
time.sleep(10) time.sleep(10)
@ -180,7 +180,7 @@ class MpcHcApi:
if self.callbacks.onMpcClosed: if self.callbacks.onMpcClosed:
self.callbacks.onMpcClosed(None) self.callbacks.onMpcClosed(None)
break break
CMD_CONNECT = 0x50000000 CMD_CONNECT = 0x50000000
CMD_STATE = 0x50000001 CMD_STATE = 0x50000001
CMD_PLAYMODE = 0x50000002 CMD_PLAYMODE = 0x50000002
@ -225,13 +225,13 @@ class MpcHcApi:
CMD_PAUSE = 0xA0000005 CMD_PAUSE = 0xA0000005
CMD_GETVERSION = 0xA0003006 CMD_GETVERSION = 0xA0003006
CMD_SETSPEED = 0xA0004008 CMD_SETSPEED = 0xA0004008
class __MPC_LOADSTATE: class __MPC_LOADSTATE:
MLS_CLOSED = 0 MLS_CLOSED = 0
MLS_LOADING = 1 MLS_LOADING = 1
MLS_LOADED = 2 MLS_LOADED = 2
MLS_CLOSING = 3 MLS_CLOSING = 3
class __MPC_PLAYSTATE: class __MPC_PLAYSTATE:
PS_PLAY = 0 PS_PLAY = 0
PS_PAUSE = 1 PS_PAUSE = 1
@ -244,10 +244,10 @@ class MpcHcApi:
self.locks = locks self.locks = locks
self.mpcHandle = None self.mpcHandle = None
self.hwnd = None self.hwnd = None
self.__PCOPYDATASTRUCT = ctypes.POINTER(self.__COPYDATASTRUCT) self.__PCOPYDATASTRUCT = ctypes.POINTER(self.__COPYDATASTRUCT)
threading.Thread.__init__(self, name="MPC Listener") threading.Thread.__init__(self, name="MPC Listener")
def run(self): def run(self):
message_map = { message_map = {
win32con.WM_COPYDATA: self.OnCopyData win32con.WM_COPYDATA: self.OnCopyData
} }
@ -271,13 +271,13 @@ class MpcHcApi:
) )
self.locks.listenerStart.set() self.locks.listenerStart.set()
win32gui.PumpMessages() win32gui.PumpMessages()
def OnCopyData(self, hwnd, msg, wparam, lparam): def OnCopyData(self, hwnd, msg, wparam, lparam):
pCDS = ctypes.cast(lparam, self.__PCOPYDATASTRUCT) pCDS = ctypes.cast(lparam, self.__PCOPYDATASTRUCT)
#print "API:\tin>\t 0x%X\t" % int(pCDS.contents.dwData), ctypes.wstring_at(pCDS.contents.lpData) #print "API:\tin>\t 0x%X\t" % int(pCDS.contents.dwData), ctypes.wstring_at(pCDS.contents.lpData)
self.__mpcApi.handleCommand(pCDS.contents.dwData, ctypes.wstring_at(pCDS.contents.lpData)) self.__mpcApi.handleCommand(pCDS.contents.dwData, ctypes.wstring_at(pCDS.contents.lpData))
def SendCommand(self, cmd, message=u''): def SendCommand(self, cmd, message=u''):
#print "API:\t<out\t 0x%X\t" % int(cmd), message #print "API:\t<out\t 0x%X\t" % int(cmd), message
if not win32gui.IsWindow(self.mpcHandle): if not win32gui.IsWindow(self.mpcHandle):
@ -295,8 +295,8 @@ class MpcHcApi:
cs.lpData = ctypes.addressof(message) cs.lpData = ctypes.addressof(message)
cs.cbData = ctypes.sizeof(message) cs.cbData = ctypes.sizeof(message)
ptr = ctypes.addressof(cs) ptr = ctypes.addressof(cs)
win32api.SendMessage(self.mpcHandle, win32con.WM_COPYDATA, self.hwnd, ptr) win32api.SendMessage(self.mpcHandle, win32con.WM_COPYDATA, self.hwnd, ptr)
class __COPYDATASTRUCT(ctypes.Structure): class __COPYDATASTRUCT(ctypes.Structure):
_fields_ = [ _fields_ = [
('dwData', ctypes.wintypes.LPARAM), ('dwData', ctypes.wintypes.LPARAM),
@ -309,8 +309,9 @@ class MPCHCAPIPlayer(BasePlayer):
alertOSDSupported = False alertOSDSupported = False
customOpenDialog = False customOpenDialog = False
chatOSDSupported = False chatOSDSupported = False
alertOSDSupported = False
osdMessageSeparator = "; " osdMessageSeparator = "; "
def __init__(self, client): def __init__(self, client):
from twisted.internet import reactor from twisted.internet import reactor
self.reactor = reactor self.reactor = reactor
@ -332,7 +333,7 @@ class MPCHCAPIPlayer(BasePlayer):
@staticmethod @staticmethod
def getMinVersionErrorMessage(): def getMinVersionErrorMessage():
return getMessage("mpc-version-insufficient-error").format(constants.MPC_MIN_VER) return getMessage("mpc-version-insufficient-error").format(constants.MPC_MIN_VER)
def drop(self): def drop(self):
self.__preventAsking.set() self.__preventAsking.set()
self.__positionUpdate.set() self.__positionUpdate.set()
@ -354,29 +355,29 @@ class MPCHCAPIPlayer(BasePlayer):
def __lockAsking(self): def __lockAsking(self):
self.__preventAsking.clear() self.__preventAsking.clear()
def __unlockAsking(self): def __unlockAsking(self):
self.__preventAsking.set() self.__preventAsking.set()
def __onGetPosition(self): def __onGetPosition(self):
self.__positionUpdate.set() self.__positionUpdate.set()
def setSpeed(self, value): def setSpeed(self, value):
try: try:
self._mpcApi.setSpeed(value) self._mpcApi.setSpeed(value)
except MpcHcApi.PlayerNotReadyException: except MpcHcApi.PlayerNotReadyException:
self.setSpeed(value) self.setSpeed(value)
def __dropIfNotSufficientVersion(self): def __dropIfNotSufficientVersion(self):
self._mpcApi.askForVersion() self._mpcApi.askForVersion()
if not self.__versionUpdate.wait(0.1) or not self._mpcApi.version: if not self.__versionUpdate.wait(0.1) or not self._mpcApi.version:
self.reactor.callFromThread(self.__client.ui.showErrorMessage, self.getMinVersionErrorMessage(), True) self.reactor.callFromThread(self.__client.ui.showErrorMessage, self.getMinVersionErrorMessage(), True)
self.reactor.callFromThread(self.__client.stop, True) self.reactor.callFromThread(self.__client.stop, True)
def __testMpcReady(self): def __testMpcReady(self):
if not self.__preventAsking.wait(10): if not self.__preventAsking.wait(10):
raise Exception(getMessage("player-file-open-error")) raise Exception(getMessage("player-file-open-error"))
def __makePing(self): def __makePing(self):
try: try:
self.__testMpcReady() self.__testMpcReady()
@ -386,7 +387,7 @@ class MPCHCAPIPlayer(BasePlayer):
except Exception, err: except Exception, err:
self.reactor.callFromThread(self.__client.ui.showErrorMessage, err.message, True) self.reactor.callFromThread(self.__client.ui.showErrorMessage, err.message, True)
self.reactor.callFromThread(self.__client.stop) self.reactor.callFromThread(self.__client.stop)
def initPlayer(self, filePath): def initPlayer(self, filePath):
self.__dropIfNotSufficientVersion() self.__dropIfNotSufficientVersion()
if not self._mpcApi.version: if not self._mpcApi.version:
@ -396,10 +397,10 @@ class MPCHCAPIPlayer(BasePlayer):
self.__switchPauseCalls = True self.__switchPauseCalls = True
if filePath: if filePath:
self.openFile(filePath) self.openFile(filePath)
def openFile(self, filePath, resetPosition=False): def openFile(self, filePath, resetPosition=False):
self._mpcApi.openFile(filePath) self._mpcApi.openFile(filePath)
def displayMessage(self, message, duration = (constants.OSD_DURATION*1000), OSDType=constants.OSD_NOTIFICATION, mood=constants.MESSAGE_NEUTRAL): def displayMessage(self, message, duration = (constants.OSD_DURATION*1000), OSDType=constants.OSD_NOTIFICATION, mood=constants.MESSAGE_NEUTRAL):
self._mpcApi.sendOsd(message, constants.MPC_OSD_POSITION, duration) self._mpcApi.sendOsd(message, constants.MPC_OSD_POSITION, duration)
@ -412,12 +413,12 @@ class MPCHCAPIPlayer(BasePlayer):
self._mpcApi.pause() self._mpcApi.pause()
else: else:
self._mpcApi.unpause() self._mpcApi.unpause()
@retry(MpcHcApi.PlayerNotReadyException, constants.MPC_MAX_RETRIES, constants.MPC_RETRY_WAIT_TIME, 1) @retry(MpcHcApi.PlayerNotReadyException, constants.MPC_MAX_RETRIES, constants.MPC_RETRY_WAIT_TIME, 1)
def setPosition(self, value): def setPosition(self, value):
if self._mpcApi.filePlaying: if self._mpcApi.filePlaying:
self._mpcApi.seek(value) self._mpcApi.seek(value)
def __getPosition(self): def __getPosition(self):
self.__positionUpdate.clear() self.__positionUpdate.clear()
self._mpcApi.askForCurrentPosition() self._mpcApi.askForCurrentPosition()
@ -446,9 +447,9 @@ class MPCHCAPIPlayer(BasePlayer):
for _ in xrange(constants.MPC_MAX_RETRIES): for _ in xrange(constants.MPC_MAX_RETRIES):
self.setPaused(True) self.setPaused(True)
time.sleep(constants.MPC_RETRY_WAIT_TIME) time.sleep(constants.MPC_RETRY_WAIT_TIME)
def __refreshMpcPlayState(self): def __refreshMpcPlayState(self):
for _ in xrange(2): for _ in xrange(2):
self._mpcApi.playPause() self._mpcApi.playPause()
time.sleep(constants.MPC_PAUSE_TOGGLE_DELAY) time.sleep(constants.MPC_PAUSE_TOGGLE_DELAY)
@ -459,12 +460,12 @@ class MPCHCAPIPlayer(BasePlayer):
self.__refreshMpcPlayState() self.__refreshMpcPlayState()
if self._mpcApi.isPaused() <> self.__client.getGlobalPaused(): if self._mpcApi.isPaused() <> self.__client.getGlobalPaused():
self.__setUpStateForNewlyOpenedFile() self.__setUpStateForNewlyOpenedFile()
@retry(MpcHcApi.PlayerNotReadyException, constants.MPC_MAX_RETRIES, constants.MPC_RETRY_WAIT_TIME, 1) @retry(MpcHcApi.PlayerNotReadyException, constants.MPC_MAX_RETRIES, constants.MPC_RETRY_WAIT_TIME, 1)
def __setUpStateForNewlyOpenedFile(self): def __setUpStateForNewlyOpenedFile(self):
self._setPausedAccordinglyToServer() self._setPausedAccordinglyToServer()
self._mpcApi.seek(self.__client.getGlobalPosition()) self._mpcApi.seek(self.__client.getGlobalPosition())
def __handleUpdatedFilename(self): def __handleUpdatedFilename(self):
with self.__fileUpdate: with self.__fileUpdate:
self.__setUpStateForNewlyOpenedFile() self.__setUpStateForNewlyOpenedFile()
@ -473,18 +474,18 @@ class MPCHCAPIPlayer(BasePlayer):
def sendCustomCommand(self, cmd, val): def sendCustomCommand(self, cmd, val):
self._mpcApi.sendRawCommand(cmd, val) self._mpcApi.sendRawCommand(cmd, val)
@staticmethod @staticmethod
def getDefaultPlayerPathsList(): def getDefaultPlayerPathsList():
return constants.MPC_PATHS return constants.MPC_PATHS
@staticmethod @staticmethod
def getIconPath(path): def getIconPath(path):
if MPCHCAPIPlayer.getExpandedPath(path).lower().endswith(u'mpc-hc64.exe'.lower()): if MPCHCAPIPlayer.getExpandedPath(path).lower().endswith(u'mpc-hc64.exe'.lower()):
return constants.MPC64_ICONPATH return constants.MPC64_ICONPATH
else: else:
return constants.MPC_ICONPATH return constants.MPC_ICONPATH
@staticmethod @staticmethod
def isValidPlayerPath(path): def isValidPlayerPath(path):
if MPCHCAPIPlayer.getExpandedPath(path): if MPCHCAPIPlayer.getExpandedPath(path):