Fixes on mpc-api
This commit is contained in:
parent
777a3a66f0
commit
4fda98492b
@ -15,7 +15,10 @@ def prepare_args(args):
|
|||||||
args.args.extend(['/open', '/new'])
|
args.args.extend(['/open', '/new'])
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
args = utils.get_configuration()
|
try:
|
||||||
prepare_args(args)
|
args = utils.get_configuration()
|
||||||
manager = client.Manager(args.host, args.port, args.name, lambda m: mpc_using_api.run_mpc(m, args.mpc_path, args.file, args.args))
|
prepare_args(args)
|
||||||
manager.start()
|
manager = client.Manager(args.host, args.port, args.name, lambda m: mpc_using_api.run_mpc(m, args.mpc_path, args.file, args.args))
|
||||||
|
manager.start()
|
||||||
|
finally:
|
||||||
|
manager.stop()
|
||||||
|
|||||||
@ -212,6 +212,7 @@ class Manager(object):
|
|||||||
command_handler = threading.Thread(target = utils.stdin_thread, args = (self,), name = "Command handler")
|
command_handler = threading.Thread(target = utils.stdin_thread, args = (self,), name = "Command handler")
|
||||||
command_handler.setDaemon(True)
|
command_handler.setDaemon(True)
|
||||||
command_handler.start()
|
command_handler.start()
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
if self.running:
|
if self.running:
|
||||||
return
|
return
|
||||||
|
|||||||
@ -1,29 +1,22 @@
|
|||||||
#coding:utf8
|
#coding:utf8
|
||||||
|
|
||||||
|
import threading,time,thread
|
||||||
import win32con, win32api, win32gui, ctypes, ctypes.wintypes
|
import win32con, win32api, win32gui, ctypes, ctypes.wintypes
|
||||||
import os, thread
|
|
||||||
|
|
||||||
class MPC_API:
|
class MPC_API:
|
||||||
def __init__(self, enforce_custom_handler = False):
|
def __init__(self, enforce_custom_handler = False):
|
||||||
self.enforce_custom_handler = enforce_custom_handler
|
|
||||||
self.__listener = None
|
|
||||||
thread.start_new_thread(self.__Listener, (self,))
|
|
||||||
while(self.__listener == None): continue
|
|
||||||
self.__position_request_warden = False
|
|
||||||
self.__seek_warden = False
|
|
||||||
self.__playpause_warden = False
|
|
||||||
'''
|
'''
|
||||||
List of callbacks that can be set
|
List of callbacks that can be set
|
||||||
Each callback by default receives a tuple argument, can be empty though
|
on_connected (0 args)
|
||||||
on_connected
|
on_seek (0 args)
|
||||||
on_seek
|
on_update_filename (filename)
|
||||||
on_update_filename
|
on_update_file_duration (duration)
|
||||||
on_update_file_duration
|
on_update_position (positon)
|
||||||
on_update_position
|
on_update_playstate (playstate)
|
||||||
on_update_playstate
|
on_file_ready (filename)
|
||||||
on_file_ready
|
custom_handler (cmd, value)
|
||||||
custom_handler
|
|
||||||
'''
|
'''
|
||||||
|
self.enforce_custom_handler = enforce_custom_handler
|
||||||
self.callbacks = self.__CALLBACKS()
|
self.callbacks = self.__CALLBACKS()
|
||||||
self.loadstate = None
|
self.loadstate = None
|
||||||
self.playstate = None
|
self.playstate = None
|
||||||
@ -33,30 +26,33 @@ class MPC_API:
|
|||||||
Most likely won't be up to date unless you ask API to refresh it
|
Most likely won't be up to date unless you ask API to refresh it
|
||||||
'''
|
'''
|
||||||
self.lastfileposition = None
|
self.lastfileposition = None
|
||||||
|
self.__playpause_warden = False
|
||||||
|
self.__locks = self.__LOCKS()
|
||||||
|
self.__mpc_ready_checking = threading.Thread(target = self.__mpc_ready_in_slave_mode, name ="Check MPC window")
|
||||||
|
self.__mpc_ready_checking.setDaemon(True)
|
||||||
|
self.__listener = self.__Listener(self, self.__locks)
|
||||||
|
self.__listener.setDaemon(True)
|
||||||
|
self.__listener.start()
|
||||||
|
self.__locks.listner_start.wait()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
'''
|
|
||||||
This is called from another thread and if it could it would be a private method
|
|
||||||
Developers should not bother with it
|
|
||||||
'''
|
|
||||||
def register_listener(self, listener):
|
|
||||||
self.__listener = listener
|
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Given a path fo mpc-hc.exe and optional additional arguments in tuple
|
Given a path fo mpc-hc.exe and optional additional arguments in tuple
|
||||||
will start mpc-hc in a slave mode
|
will start mpc-hc in a slave mode
|
||||||
'''
|
'''
|
||||||
def start_mpc(self, path, args = ()):
|
def start_mpc(self, path, args = ()):
|
||||||
is_starting = os.spawnl(os.P_NOWAIT, path, ' ' + ' '.join(args),'/slave %s ' % str(self.__listener.hwnd)) #can be switched with win32api.ShellExecute
|
args = "%s /slave %s" % (" ".join(args), str(self.__listener.hwnd))
|
||||||
while(self.__listener.mpc_handle == None and is_starting): continue
|
win32api.ShellExecute(0, "open", path, args, None, 1)
|
||||||
|
if(not self.__locks.mpc_start.wait(10)):
|
||||||
|
raise MPC_API.NoSlaveDetectedException("Unable to start MPC in slave mode!")
|
||||||
|
self.__mpc_ready_checking.start()
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Checks if api is ready to receive commands
|
Checks if api is ready to receive commands
|
||||||
Throws MPC_API.NoSlaveDetectedException if mpc window is not found
|
Throws MPC_API.NoSlaveDetectedException if mpc window is not found
|
||||||
'''
|
'''
|
||||||
def is_api_ready(self):
|
def is_api_ready(self):
|
||||||
self.__mpc_ready_in_slave_mode()
|
|
||||||
file_state_ok = self.loadstate == self.__MPC_LOADSTATE.MLS_CLOSED or self.loadstate == self.__MPC_LOADSTATE.MLS_LOADED or self.loadstate == None
|
file_state_ok = self.loadstate == self.__MPC_LOADSTATE.MLS_CLOSED or self.loadstate == self.__MPC_LOADSTATE.MLS_LOADED or self.loadstate == None
|
||||||
listener_ok = self.__listener <> None and self.__listener.mpc_handle <> None
|
listener_ok = self.__listener <> None and self.__listener.mpc_handle <> None
|
||||||
return (file_state_ok and listener_ok)
|
return (file_state_ok and listener_ok)
|
||||||
@ -66,7 +62,6 @@ class MPC_API:
|
|||||||
Throws MPC_API.NoSlaveDetectedException if mpc window is not found
|
Throws MPC_API.NoSlaveDetectedException if mpc window is not found
|
||||||
'''
|
'''
|
||||||
def is_file_ready(self):
|
def is_file_ready(self):
|
||||||
self.__mpc_ready_in_slave_mode()
|
|
||||||
return (self.loadstate == self.__MPC_LOADSTATE.MLS_LOADED and self.fileplaying and self.playstate <> None)
|
return (self.loadstate == self.__MPC_LOADSTATE.MLS_LOADED and self.fileplaying and self.playstate <> None)
|
||||||
|
|
||||||
'''
|
'''
|
||||||
@ -74,7 +69,6 @@ class MPC_API:
|
|||||||
Throws MPC_API.NoSlaveDetectedException if mpc window is not found
|
Throws MPC_API.NoSlaveDetectedException if mpc window is not found
|
||||||
'''
|
'''
|
||||||
def open_file(self, file_path):
|
def open_file(self, file_path):
|
||||||
self.__mpc_ready_in_slave_mode()
|
|
||||||
self.__listener.SendCommand(MPC_API_COMMANDS.CMD_OPENFILE, file_path)
|
self.__listener.SendCommand(MPC_API_COMMANDS.CMD_OPENFILE, file_path)
|
||||||
|
|
||||||
'''
|
'''
|
||||||
@ -82,7 +76,6 @@ class MPC_API:
|
|||||||
Throws MPC_API.NoSlaveDetectedException if mpc window is not found
|
Throws MPC_API.NoSlaveDetectedException if mpc window is not found
|
||||||
'''
|
'''
|
||||||
def is_paused(self):
|
def is_paused(self):
|
||||||
self.__mpc_ready_in_slave_mode()
|
|
||||||
return (self.playstate <> self.__MPC_PLAYSTATE.PS_PLAY and self.playstate <> None)
|
return (self.playstate <> self.__MPC_PLAYSTATE.PS_PLAY and self.playstate <> None)
|
||||||
|
|
||||||
'''
|
'''
|
||||||
@ -90,39 +83,31 @@ class MPC_API:
|
|||||||
Throws MPC_API.NoSlaveDetectedException if mpc window is not found
|
Throws MPC_API.NoSlaveDetectedException if mpc window is not found
|
||||||
'''
|
'''
|
||||||
def pause(self):
|
def pause(self):
|
||||||
self.__mpc_ready_in_slave_mode()
|
if(not self.is_file_ready()): raise MPC_API.PlayerNotReadyException("Playstate change on no file")
|
||||||
while(self.playstate == None):self.__mpc_ready_in_slave_mode()
|
if(not self.is_paused()):
|
||||||
if(not self.is_paused() and self.__playpause_warden == False):
|
self.playpause()
|
||||||
self.__playpause_warden = True
|
|
||||||
self.__listener.SendCommand(MPC_API_COMMANDS.CMD_PLAYPAUSE)
|
|
||||||
while(not self.is_paused()): self.__mpc_ready_in_slave_mode()
|
|
||||||
self.__playpause_warden = False
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Play paused file
|
Play paused file
|
||||||
Throws MPC_API.NoSlaveDetectedException if mpc window is not found
|
Throws MPC_API.NoSlaveDetectedException if mpc window is not found
|
||||||
'''
|
'''
|
||||||
def unpause(self):
|
def unpause(self):
|
||||||
self.__mpc_ready_in_slave_mode()
|
if(not self.is_file_ready()): raise MPC_API.PlayerNotReadyException("Playstate change on no file")
|
||||||
while(self.playstate == None):self.__mpc_ready_in_slave_mode()
|
if(self.is_paused()):
|
||||||
if(self.is_paused() and self.__playpause_warden == False):
|
self.playpause()
|
||||||
self.__playpause_warden = True
|
|
||||||
self.__listener.SendCommand(MPC_API_COMMANDS.CMD_PLAYPAUSE)
|
|
||||||
while(self.is_paused()): self.__mpc_ready_in_slave_mode()
|
|
||||||
self.__playpause_warden = False
|
|
||||||
'''
|
'''
|
||||||
Toggle play/pause
|
Toggle play/pause
|
||||||
Throws MPC_API.NoSlaveDetectedException if mpc window is not found
|
Throws MPC_API.NoSlaveDetectedException if mpc window is not found
|
||||||
'''
|
'''
|
||||||
def playpause(self):
|
def playpause(self):
|
||||||
self.__mpc_ready_in_slave_mode()
|
if(not self.is_file_ready()): raise MPC_API.PlayerNotReadyException("Playstate change on no file")
|
||||||
tmp = self.playstate
|
tmp = self.playstate
|
||||||
while(self.playstate == None):self.__mpc_ready_in_slave_mode()
|
|
||||||
if(self.__playpause_warden == False):
|
if(self.__playpause_warden == False):
|
||||||
self.__playpause_warden = True
|
self.__playpause_warden = True
|
||||||
self.__listener.SendCommand(MPC_API_COMMANDS.CMD_PLAYPAUSE)
|
self.__listener.SendCommand(MPC_API_COMMANDS.CMD_PLAYPAUSE)
|
||||||
while(tmp == self.playstate): self.__mpc_ready_in_slave_mode()
|
while(tmp == self.playstate and self.__playpause_warden): continue
|
||||||
self.__playpause_warden = False
|
self.__playpause_warden = False
|
||||||
|
if(tmp == self.playstate): self.playpause() #playstate changed manualy after issuing a command
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Asks mpc for it's current file position, if on_update_position callback is set
|
Asks mpc for it's current file position, if on_update_position callback is set
|
||||||
@ -130,22 +115,23 @@ class MPC_API:
|
|||||||
Throws MPC_API.NoSlaveDetectedException if mpc window is not found
|
Throws MPC_API.NoSlaveDetectedException if mpc window is not found
|
||||||
'''
|
'''
|
||||||
def ask_for_current_position(self):
|
def ask_for_current_position(self):
|
||||||
self.__mpc_ready_in_slave_mode()
|
if(not self.is_file_ready()):
|
||||||
if(not self.__position_request_warden):
|
raise MPC_API.PlayerNotReadyException("File not yet ready")
|
||||||
self.__position_request_warden = True
|
self.__locks.positionget.clear()
|
||||||
self.__listener.SendCommand(MPC_API_COMMANDS.CMD_GETCURRENTPOSITION)
|
self.__listener.SendCommand(MPC_API_COMMANDS.CMD_GETCURRENTPOSITION)
|
||||||
while(self.__position_request_warden and not self.callbacks.on_update_position): self.__mpc_ready_in_slave_mode()
|
if(not self.callbacks.on_update_position):
|
||||||
return self.lastfileposition
|
if(not self.__locks.positionget.wait(0.2)):
|
||||||
|
raise MPC_API.PlayerNotReadyException("Position get fail")
|
||||||
|
return self.lastfileposition
|
||||||
'''
|
'''
|
||||||
Given a position in seconds will ask client to seek there
|
Given a position in seconds will ask client to seek there
|
||||||
Throws MPC_API.NoSlaveDetectedException if mpc window is not found
|
Throws MPC_API.NoSlaveDetectedException if mpc window is not found
|
||||||
'''
|
'''
|
||||||
def seek(self, position):
|
def seek(self, position):
|
||||||
self.__mpc_ready_in_slave_mode()
|
self.__locks.seek.clear()
|
||||||
self.__seek_warden = True
|
|
||||||
self.__listener.SendCommand(MPC_API_COMMANDS.CMD_SETPOSITION, unicode(position))
|
self.__listener.SendCommand(MPC_API_COMMANDS.CMD_SETPOSITION, unicode(position))
|
||||||
while(self.__seek_warden): self.__mpc_ready_in_slave_mode()
|
if(not self.__locks.seek.wait(0.2)):
|
||||||
|
raise MPC_API.PlayerNotReadyException("Seek fail")
|
||||||
'''
|
'''
|
||||||
@param message: unicode string to display in player
|
@param message: unicode string to display in player
|
||||||
@param MsgPos: Either 1, left top corner or 2, right top corner, defaults to 2
|
@param MsgPos: Either 1, left top corner or 2, right top corner, defaults to 2
|
||||||
@ -153,7 +139,6 @@ class MPC_API:
|
|||||||
Throws MPC_API.NoSlaveDetectedException if mpc window is not found
|
Throws MPC_API.NoSlaveDetectedException if mpc window is not found
|
||||||
'''
|
'''
|
||||||
def send_osd(self, message, MsgPos = 2, DurationMs = 3000):
|
def send_osd(self, message, MsgPos = 2, DurationMs = 3000):
|
||||||
self.__mpc_ready_in_slave_mode()
|
|
||||||
class __OSDDATASTRUCT(ctypes.Structure):
|
class __OSDDATASTRUCT(ctypes.Structure):
|
||||||
_fields_ = [
|
_fields_ = [
|
||||||
('nMsgPos', ctypes.c_int32),
|
('nMsgPos', ctypes.c_int32),
|
||||||
@ -173,7 +158,6 @@ class MPC_API:
|
|||||||
Throws MPC_API.NoSlaveDetectedException if mpc window is not found
|
Throws MPC_API.NoSlaveDetectedException if mpc window is not found
|
||||||
'''
|
'''
|
||||||
def send_raw_command(self, cmd, value):
|
def send_raw_command(self, cmd, value):
|
||||||
self.__mpc_ready_in_slave_mode()
|
|
||||||
self.__listener.SendCommand(cmd, value)
|
self.__listener.SendCommand(cmd, value)
|
||||||
|
|
||||||
'''
|
'''
|
||||||
@ -184,44 +168,49 @@ class MPC_API:
|
|||||||
'''
|
'''
|
||||||
def handle_command(self,cmd, value, enforce_custom_handler = False):
|
def handle_command(self,cmd, value, enforce_custom_handler = False):
|
||||||
if((self.enforce_custom_handler or enforce_custom_handler) and self.callbacks.custom_handler <> None):
|
if((self.enforce_custom_handler or enforce_custom_handler) and self.callbacks.custom_handler <> None):
|
||||||
self.callbacks.custom_handler((cmd, value,))
|
thread.start_new_thread(self.callbacks.custom_handler,(cmd, value,))
|
||||||
else:
|
else:
|
||||||
if (cmd == MPC_API_COMMANDS.CMD_CONNECT):
|
if (cmd == MPC_API_COMMANDS.CMD_CONNECT):
|
||||||
self.__listener.mpc_handle = int(value)
|
self.__listener.mpc_handle = int(value)
|
||||||
|
self.__locks.mpc_start.set()
|
||||||
if(self.callbacks.on_connected):
|
if(self.callbacks.on_connected):
|
||||||
self.callbacks.on_connected(())
|
thread.start_new_thread(self.callbacks.on_connected, ())
|
||||||
|
|
||||||
elif(cmd == MPC_API_COMMANDS.CMD_STATE):
|
elif(cmd == MPC_API_COMMANDS.CMD_STATE):
|
||||||
self.loadstate = int(value)
|
self.loadstate = int(value)
|
||||||
|
|
||||||
elif(cmd == MPC_API_COMMANDS.CMD_PLAYMODE):
|
elif(cmd == MPC_API_COMMANDS.CMD_PLAYMODE):
|
||||||
self.playstate = int(value)
|
self.playstate = int(value)
|
||||||
if(self.callbacks.on_update_playstate): self.callbacks.on_update_playstate((self.playstate,))
|
if(self.callbacks.on_update_playstate): thread.start_new_thread(self.callbacks.on_update_playstate,(self.playstate,))
|
||||||
|
|
||||||
elif(cmd == MPC_API_COMMANDS.CMD_NOWPLAYING):
|
elif(cmd == MPC_API_COMMANDS.CMD_NOWPLAYING):
|
||||||
if(self.callbacks.on_file_ready): self.callbacks.on_file_ready(())
|
|
||||||
self.fileplaying = value.split('|')[3].split('\\').pop()
|
self.fileplaying = value.split('|')[3].split('\\').pop()
|
||||||
if(self.callbacks.on_update_filename): self.callbacks.on_update_filename((self.fileplaying,))
|
if(self.callbacks.on_update_filename): thread.start_new_thread(self.callbacks.on_update_filename,(self.fileplaying,))
|
||||||
self.fileduration = int(value.split('|')[4])
|
self.fileduration = int(value.split('|')[4])
|
||||||
if(self.callbacks.on_update_file_duration): self.callbacks.on_update_file_duration((self.fileplaying,))
|
if(self.callbacks.on_update_file_duration): thread.start_new_thread(self.callbacks.on_update_file_duration,(self.fileplaying,))
|
||||||
|
if(self.callbacks.on_file_ready): thread.start_new_thread(self.callbacks.on_file_ready, ())
|
||||||
|
|
||||||
elif(cmd == MPC_API_COMMANDS.CMD_CURRENTPOSITION):
|
elif(cmd == MPC_API_COMMANDS.CMD_CURRENTPOSITION):
|
||||||
self.lastfileposition = float(value)
|
self.lastfileposition = float(value)
|
||||||
self.__position_request_warden = False
|
self.__locks.positionget.set()
|
||||||
if(self.callbacks.on_update_position): self.callbacks.on_update_position((self.lastfileposition,))
|
if(self.callbacks.on_update_position): thread.start_new_thread(self.callbacks.on_update_position,(self.lastfileposition,))
|
||||||
|
|
||||||
elif(cmd == MPC_API_COMMANDS.CMD_NOTIFYSEEK):
|
elif(cmd == MPC_API_COMMANDS.CMD_NOTIFYSEEK):
|
||||||
self.__seek_warden = False
|
self.__locks.seek.set()
|
||||||
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.on_seek): self.callbacks.on_seek((self.lastfileposition,))
|
if(self.callbacks.on_seek): thread.start_new_thread(self.callbacks.on_seek,(self.lastfileposition,))
|
||||||
else:
|
else:
|
||||||
if(self.callbacks.custom_handler <> None):
|
if(self.callbacks.custom_handler <> None):
|
||||||
self.callbacks.custom_handler((cmd, value,))
|
thread.start_new_thread(self.callbacks.custom_handler,(cmd, value,))
|
||||||
|
|
||||||
class NoSlaveDetectedException(Exception):
|
class NoSlaveDetectedException(Exception):
|
||||||
def __init__(self, message):
|
def __init__(self, message):
|
||||||
Exception.__init__(self, message)
|
Exception.__init__(self, message)
|
||||||
|
class PlayerNotReadyException(Exception):
|
||||||
|
def __init__(self, message):
|
||||||
|
Exception.__init__(self, message)
|
||||||
|
|
||||||
|
|
||||||
class __CALLBACKS:
|
class __CALLBACKS:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -233,12 +222,22 @@ class MPC_API:
|
|||||||
self.on_update_playstate = None
|
self.on_update_playstate = None
|
||||||
self.on_file_ready = None
|
self.on_file_ready = None
|
||||||
self.custom_handler = None
|
self.custom_handler = None
|
||||||
|
self.on_mpc_closed = None
|
||||||
|
|
||||||
|
class __LOCKS:
|
||||||
|
def __init__(self):
|
||||||
|
self.listner_start = threading.Event()
|
||||||
|
self.mpc_start = threading.Event()
|
||||||
|
self.positionget = threading.Event()
|
||||||
|
self.seek = threading.Event()
|
||||||
|
|
||||||
|
|
||||||
def __mpc_ready_in_slave_mode(self):
|
def __mpc_ready_in_slave_mode(self):
|
||||||
if not win32gui.IsWindow(self.__listener.mpc_handle):
|
while(True):
|
||||||
raise MPC_API.NoSlaveDetectedException("MPC Slave Window not detected")
|
time.sleep(1)
|
||||||
|
if not win32gui.IsWindow(self.__listener.mpc_handle):
|
||||||
|
self.callbacks.on_mpc_closed()
|
||||||
|
break
|
||||||
|
|
||||||
class __MPC_LOADSTATE:
|
class __MPC_LOADSTATE:
|
||||||
MLS_CLOSED = 0
|
MLS_CLOSED = 0
|
||||||
MLS_LOADING = 1
|
MLS_LOADING = 1
|
||||||
@ -259,9 +258,16 @@ class MPC_API:
|
|||||||
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
class __Listener:
|
class __Listener(threading.Thread):
|
||||||
def __init__(self, mpc_api):
|
def __init__(self, mpc_api, locks):
|
||||||
|
self.__mpc_api = mpc_api
|
||||||
|
self.locks = locks
|
||||||
self.mpc_handle = None
|
self.mpc_handle = None
|
||||||
|
self.hwnd = None
|
||||||
|
self.__PCOPYDATASTRUCT = ctypes.POINTER(self.__COPYDATASTRUCT)
|
||||||
|
threading.Thread.__init__(self, name="MPC Listener")
|
||||||
|
|
||||||
|
def run(self):
|
||||||
message_map = {
|
message_map = {
|
||||||
win32con.WM_COPYDATA: self.OnCopyData
|
win32con.WM_COPYDATA: self.OnCopyData
|
||||||
}
|
}
|
||||||
@ -283,11 +289,9 @@ class MPC_API:
|
|||||||
hinst,
|
hinst,
|
||||||
None
|
None
|
||||||
)
|
)
|
||||||
self.__PCOPYDATASTRUCT = ctypes.POINTER(self.__COPYDATASTRUCT)
|
self.locks.listner_start.set()
|
||||||
self.__mpc_api = mpc_api
|
|
||||||
|
|
||||||
mpc_api.register_listener(self)
|
|
||||||
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)
|
||||||
@ -321,130 +325,44 @@ class MPC_API:
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class MPC_API_COMMANDS():
|
class MPC_API_COMMANDS():
|
||||||
# Send after connection
|
|
||||||
# Par 1 : MPC window handle (command should be send to this HWnd)
|
|
||||||
CMD_CONNECT = 0x50000000
|
CMD_CONNECT = 0x50000000
|
||||||
# Send when opening or closing file
|
|
||||||
# Par 1 : current state (see MPC_LOADSTATE enum)
|
|
||||||
CMD_STATE = 0x50000001
|
CMD_STATE = 0x50000001
|
||||||
# Send when playing, pausing or closing file
|
|
||||||
# Par 1 : current play mode (see MPC_PLAYSTATE enum)
|
|
||||||
CMD_PLAYMODE = 0x50000002
|
CMD_PLAYMODE = 0x50000002
|
||||||
# Send after opening a new file
|
|
||||||
# Par 1 : title
|
|
||||||
# Par 2 : author
|
|
||||||
# Par 3 : description
|
|
||||||
# Par 4 : complete filename (path included)
|
|
||||||
# Par 5 : duration in seconds
|
|
||||||
CMD_NOWPLAYING = 0x50000003
|
CMD_NOWPLAYING = 0x50000003
|
||||||
# List of subtitle tracks
|
|
||||||
# Par 1 : Subtitle track name 0
|
|
||||||
# Par 2 : Subtitle track name 1
|
|
||||||
# ...
|
|
||||||
# Par n : Active subtitle track, -1 if subtitles disabled
|
|
||||||
#
|
|
||||||
# if no subtitle track present, returns -1
|
|
||||||
# if no file loaded, returns -2
|
|
||||||
CMD_LISTSUBTITLETRACKS = 0x50000004
|
CMD_LISTSUBTITLETRACKS = 0x50000004
|
||||||
# List of audio tracks
|
|
||||||
# Par 1 : Audio track name 0
|
|
||||||
# Par 2 : Audio track name 1
|
|
||||||
# ...
|
|
||||||
# Par n : Active audio track
|
|
||||||
#
|
|
||||||
# if no audio track present, returns -1
|
|
||||||
# if no file loaded, returns -2
|
|
||||||
CMD_LISTAUDIOTRACKS = 0x50000005
|
CMD_LISTAUDIOTRACKS = 0x50000005
|
||||||
# Send current playback position in responce
|
|
||||||
# of CMD_GETCURRENTPOSITION.
|
|
||||||
# Par 1 : current position in seconds
|
|
||||||
CMD_CURRENTPOSITION = 0x50000007
|
CMD_CURRENTPOSITION = 0x50000007
|
||||||
# Send the current playback position after a jump.
|
|
||||||
# (Automatically sent after a seek event).
|
|
||||||
# Par 1 : new playback position (in seconds).
|
|
||||||
CMD_NOTIFYSEEK = 0x50000008
|
CMD_NOTIFYSEEK = 0x50000008
|
||||||
# Notify the end of current playback
|
|
||||||
# (Automatically sent).
|
|
||||||
# Par 1 : none.
|
|
||||||
CMD_NOTIFYENDOFSTREAM = 0x50000009
|
CMD_NOTIFYENDOFSTREAM = 0x50000009
|
||||||
# List of files in the playlist
|
|
||||||
# Par 1 : file path 0
|
|
||||||
# Par 2 : file path 1
|
|
||||||
# ...
|
|
||||||
# Par n : active file, -1 if no active file
|
|
||||||
CMD_PLAYLIST = 0x50000006
|
CMD_PLAYLIST = 0x50000006
|
||||||
# ==== Commands from host to MPC
|
|
||||||
# Open new file
|
|
||||||
# Par 1 : file path
|
|
||||||
CMD_OPENFILE = 0xA0000000
|
CMD_OPENFILE = 0xA0000000
|
||||||
# Stop playback, but keep file / playlist
|
|
||||||
CMD_STOP = 0xA0000001
|
CMD_STOP = 0xA0000001
|
||||||
# Stop playback and close file / playlist
|
|
||||||
CMD_CLOSEFILE = 0xA0000002
|
CMD_CLOSEFILE = 0xA0000002
|
||||||
# Pause or restart playback
|
|
||||||
CMD_PLAYPAUSE = 0xA0000003
|
CMD_PLAYPAUSE = 0xA0000003
|
||||||
# Add a new file to playlist (did not start playing)
|
|
||||||
# Par 1 : file path
|
|
||||||
CMD_ADDTOPLAYLIST = 0xA0001000
|
CMD_ADDTOPLAYLIST = 0xA0001000
|
||||||
# Remove all files from playlist
|
|
||||||
CMD_CLEARPLAYLIST = 0xA0001001
|
CMD_CLEARPLAYLIST = 0xA0001001
|
||||||
# Start playing playlist
|
|
||||||
CMD_STARTPLAYLIST = 0xA0001002
|
CMD_STARTPLAYLIST = 0xA0001002
|
||||||
CMD_REMOVEFROMPLAYLIST = 0xA0001003 # TODO
|
CMD_REMOVEFROMPLAYLIST = 0xA0001003 # TODO
|
||||||
# Cue current file to specific position
|
|
||||||
# Par 1 : new position in seconds
|
|
||||||
CMD_SETPOSITION = 0xA0002000
|
CMD_SETPOSITION = 0xA0002000
|
||||||
# Set the audio delay
|
|
||||||
# Par 1 : new audio delay in ms
|
|
||||||
CMD_SETAUDIODELAY = 0xA0002001
|
CMD_SETAUDIODELAY = 0xA0002001
|
||||||
# Set the subtitle delay
|
|
||||||
# Par 1 : new subtitle delay in ms
|
|
||||||
CMD_SETSUBTITLEDELAY = 0xA0002002
|
CMD_SETSUBTITLEDELAY = 0xA0002002
|
||||||
# Set the active file in the playlist
|
CMD_SETINDEXPLAYLIST = 0xA0002003 # DOESNT WORK
|
||||||
# Par 1 : index of the active file, -1 for no file selected
|
|
||||||
# DOESNT WORK
|
|
||||||
CMD_SETINDEXPLAYLIST = 0xA0002003
|
|
||||||
# Set the audio track
|
|
||||||
# Par 1 : index of the audio track
|
|
||||||
CMD_SETAUDIOTRACK = 0xA0002004
|
CMD_SETAUDIOTRACK = 0xA0002004
|
||||||
# Set the subtitle track
|
|
||||||
# Par 1 : index of the subtitle track, -1 for disabling subtitles
|
|
||||||
CMD_SETSUBTITLETRACK = 0xA0002005
|
CMD_SETSUBTITLETRACK = 0xA0002005
|
||||||
# Ask for a list of the subtitles tracks of the file
|
|
||||||
# return a CMD_LISTSUBTITLETRACKS
|
|
||||||
CMD_GETSUBTITLETRACKS = 0xA0003000
|
CMD_GETSUBTITLETRACKS = 0xA0003000
|
||||||
# Ask for the current playback position,
|
|
||||||
# see CMD_CURRENTPOSITION.
|
|
||||||
# Par 1 : current position in seconds
|
|
||||||
CMD_GETCURRENTPOSITION = 0xA0003004
|
CMD_GETCURRENTPOSITION = 0xA0003004
|
||||||
# Jump forward/backward of N seconds,
|
|
||||||
# Par 1 : seconds (negative values for backward)
|
|
||||||
CMD_JUMPOFNSECONDS = 0xA0003005
|
CMD_JUMPOFNSECONDS = 0xA0003005
|
||||||
# Ask for a list of the audio tracks of the file
|
|
||||||
# return a CMD_LISTAUDIOTRACKS
|
|
||||||
CMD_GETAUDIOTRACKS = 0xA0003001
|
CMD_GETAUDIOTRACKS = 0xA0003001
|
||||||
# Ask for the properties of the current loaded file
|
|
||||||
# return a CMD_NOWPLAYING
|
|
||||||
CMD_GETNOWPLAYING = 0xA0003002
|
CMD_GETNOWPLAYING = 0xA0003002
|
||||||
# Ask for the current playlist
|
|
||||||
# return a CMD_PLAYLIST
|
|
||||||
CMD_GETPLAYLIST = 0xA0003003
|
CMD_GETPLAYLIST = 0xA0003003
|
||||||
# Toggle FullScreen
|
|
||||||
CMD_TOGGLEFULLSCREEN = 0xA0004000
|
CMD_TOGGLEFULLSCREEN = 0xA0004000
|
||||||
# Jump forward(medium)
|
|
||||||
CMD_JUMPFORWARDMED = 0xA0004001
|
CMD_JUMPFORWARDMED = 0xA0004001
|
||||||
# Jump backward(medium)
|
|
||||||
CMD_JUMPBACKWARDMED = 0xA0004002
|
CMD_JUMPBACKWARDMED = 0xA0004002
|
||||||
# Increase Volume
|
|
||||||
CMD_INCREASEVOLUME = 0xA0004003
|
CMD_INCREASEVOLUME = 0xA0004003
|
||||||
# Decrease volume
|
|
||||||
CMD_DECREASEVOLUME = 0xA0004004
|
CMD_DECREASEVOLUME = 0xA0004004
|
||||||
# Shader toggle
|
|
||||||
CMD_SHADER_TOGGLE = 0xA0004005
|
CMD_SHADER_TOGGLE = 0xA0004005
|
||||||
# Close App
|
|
||||||
CMD_CLOSEAPP = 0xA0004006
|
CMD_CLOSEAPP = 0xA0004006
|
||||||
# show host defined OSD message string
|
|
||||||
CMD_OSDSHOWMESSAGE = 0xA0005000
|
CMD_OSDSHOWMESSAGE = 0xA0005000
|
||||||
|
|
||||||
|
|
||||||
@ -1,6 +1,7 @@
|
|||||||
#coding:utf8
|
#coding:utf8
|
||||||
|
|
||||||
from ..mpc_api import MPC_API
|
from ..mpc_api import MPC_API
|
||||||
from twisted.internet import reactor
|
import time
|
||||||
|
|
||||||
class MPCHCAPIPlayer(object):
|
class MPCHCAPIPlayer(object):
|
||||||
def __init__(self, manager):
|
def __init__(self, manager):
|
||||||
@ -11,24 +12,37 @@ class MPCHCAPIPlayer(object):
|
|||||||
self.tmp_filename = None
|
self.tmp_filename = None
|
||||||
self.tmp_position = None
|
self.tmp_position = None
|
||||||
|
|
||||||
self.mpc_api.callbacks.on_file_ready = lambda _: reactor.callLater(0.7,self.make_ping)
|
self.mpc_api.callbacks.on_file_ready = lambda: self.make_ping()
|
||||||
|
self.mpc_api.callbacks.on_mpc_closed = lambda: self.mpc_error("MPC closed")
|
||||||
|
|
||||||
|
self.semaphore_filename = False
|
||||||
|
|
||||||
def drop(self):
|
def drop(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def set_speed(self, value):
|
def set_speed(self, value):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def test_mpc_ready(self):
|
||||||
|
try:
|
||||||
|
self.mpc_api.ask_for_current_position()
|
||||||
|
except MPC_API.PlayerNotReadyException:
|
||||||
|
time.sleep(0.1)
|
||||||
|
self.test_mpc_ready()
|
||||||
|
return
|
||||||
|
|
||||||
def make_ping(self):
|
def make_ping(self):
|
||||||
|
self.mpc_api.callbacks.on_file_ready = None
|
||||||
|
self.test_mpc_ready()
|
||||||
self.manager.init_player(self)
|
self.manager.init_player(self)
|
||||||
self.pinged = True
|
self.pinged = True
|
||||||
self.ask_for_status()
|
self.ask_for_status()
|
||||||
self.mpc_api.callbacks.on_file_ready = None
|
|
||||||
|
|
||||||
def display_message(self, message):
|
def display_message(self, message):
|
||||||
try:
|
try:
|
||||||
self.mpc_api.send_osd(message)
|
self.mpc_api.send_osd(message)
|
||||||
except:
|
except Exception, err:
|
||||||
self.mpc_error()
|
self.mpc_error(err)
|
||||||
|
|
||||||
def set_paused(self, value):
|
def set_paused(self, value):
|
||||||
try:
|
try:
|
||||||
@ -36,49 +50,79 @@ class MPCHCAPIPlayer(object):
|
|||||||
self.mpc_api.pause()
|
self.mpc_api.pause()
|
||||||
else:
|
else:
|
||||||
self.mpc_api.unpause()
|
self.mpc_api.unpause()
|
||||||
except:
|
except MPC_API.PlayerNotReadyException:
|
||||||
self.mpc_error()
|
time.sleep(0.2)
|
||||||
|
self.set_paused(value)
|
||||||
|
return
|
||||||
|
except Exception, err:
|
||||||
|
self.mpc_error(err)
|
||||||
|
|
||||||
def set_position(self, value):
|
def set_position(self, value):
|
||||||
try:
|
try:
|
||||||
self.mpc_api.seek(value)
|
self.mpc_api.seek(value)
|
||||||
except:
|
except MPC_API.PlayerNotReadyException:
|
||||||
self.mpc_error()
|
self.set_position(value)
|
||||||
|
return
|
||||||
|
except Exception, err:
|
||||||
|
self.mpc_error(err)
|
||||||
|
|
||||||
def ask_for_status(self):
|
def ask_for_status(self):
|
||||||
position = self.tmp_position if self.tmp_position else 0
|
position = self.tmp_position if self.tmp_position else 0
|
||||||
paused = None
|
paused = None
|
||||||
try:
|
try:
|
||||||
if(self.mpc_api.is_file_ready()):
|
if(self.mpc_api.is_file_ready() and not self.semaphore_filename):
|
||||||
|
try:
|
||||||
|
position = self.mpc_api.ask_for_current_position()
|
||||||
|
except MPC_API.PlayerNotReadyException:
|
||||||
|
time.sleep(0.1)
|
||||||
|
self.ask_for_status()
|
||||||
|
return
|
||||||
if(self.tmp_filename <> self.mpc_api.fileplaying):
|
if(self.tmp_filename <> self.mpc_api.fileplaying):
|
||||||
self.handle_updated_filename(self.mpc_api.fileplaying)
|
self.handle_updated_filename(self.mpc_api.fileplaying)
|
||||||
return
|
return
|
||||||
position = self.mpc_api.ask_for_current_position()
|
|
||||||
paused = self.mpc_api.is_paused()
|
paused = self.mpc_api.is_paused()
|
||||||
position = float(position)
|
position = float(position)
|
||||||
self.tmp_position = position
|
self.tmp_position = position
|
||||||
self.manager.update_player_status(paused, position)
|
self.manager.update_player_status(paused, position)
|
||||||
else:
|
else:
|
||||||
self.manager.update_player_status(True, self.manager.get_global_position())
|
self.manager.update_player_status(True, self.manager.get_global_position())
|
||||||
except MPC_API.NoSlaveDetectedException:
|
except Exception, err:
|
||||||
self.mpc_error()
|
self.mpc_error(err)
|
||||||
|
|
||||||
def handle_updated_filename(self,filename):
|
def __force_pause(self, filename, position):
|
||||||
|
self.set_paused(True)
|
||||||
|
time.sleep(0.1)
|
||||||
|
if (not self.mpc_api.is_paused()):
|
||||||
|
self.__set_up_newly_opened_file(filename, position)
|
||||||
|
|
||||||
|
def __set_up_newly_opened_file(self, filename, position):
|
||||||
|
self.test_mpc_ready()
|
||||||
|
try:
|
||||||
|
self.mpc_api.seek(position)
|
||||||
|
except MPC_API.PlayerNotReadyException:
|
||||||
|
time.sleep(0.1)
|
||||||
|
self.__set_up_newly_opened_file(filename, position)
|
||||||
|
self.__force_pause(filename, position)
|
||||||
|
|
||||||
|
def handle_updated_filename(self, filename):
|
||||||
position = self.manager.get_global_position()
|
position = self.manager.get_global_position()
|
||||||
|
if(self.semaphore_filename):
|
||||||
|
self.manager.update_player_status(True, position)
|
||||||
|
return
|
||||||
|
self.semaphore_filename = True
|
||||||
|
self.__set_up_newly_opened_file(filename, position)
|
||||||
self.tmp_filename = filename
|
self.tmp_filename = filename
|
||||||
self.manager.update_filename(str(self.tmp_filename))
|
self.manager.update_filename(str(self.tmp_filename))
|
||||||
self.mpc_api.seek(position)
|
|
||||||
reactor.callLater(0.7, self.set_paused, True)
|
|
||||||
self.manager.update_player_status(True, position)
|
self.manager.update_player_status(True, position)
|
||||||
|
self.semaphore_filename = False
|
||||||
|
|
||||||
def mpc_error(self):
|
def mpc_error(self, err=""):
|
||||||
|
print "ERROR:", str(err) + ',', "desu"
|
||||||
if self.manager.running:
|
if self.manager.running:
|
||||||
print 'Failed to connect to MPC-HC API!'
|
print 'Failed to connect to MPC-HC API!'
|
||||||
self.manager.stop()
|
self.manager.stop()
|
||||||
|
|
||||||
|
|
||||||
def run_mpc(manager, mpc_path, file_path, args):
|
def run_mpc(manager, mpc_path, file_path, args):
|
||||||
mpc = MPCHCAPIPlayer(manager)
|
mpc = MPCHCAPIPlayer(manager)
|
||||||
mpc.mpc_api.callbacks.on_connected = lambda _: mpc.mpc_api.open_file(file_path) if(file_path) else None
|
mpc.mpc_api.callbacks.on_connected = lambda: mpc.mpc_api.open_file(file_path) if(file_path) else None
|
||||||
mpc.mpc_api.start_mpc(mpc_path, args)
|
mpc.mpc_api.start_mpc(mpc_path, args)
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user