Completly new setup
This commit is contained in:
parent
321fb5a3a5
commit
aba2117344
@ -4,10 +4,10 @@ from setuptools import find_packages
|
|||||||
|
|
||||||
common_info = dict(
|
common_info = dict(
|
||||||
name = 'SyncPlay',
|
name = 'SyncPlay',
|
||||||
version = '0.7',
|
version = '1.9',
|
||||||
author = 'Tomasz Kowalczyk, Uriziel',
|
author = 'Tomasz Kowalczyk, Uriziel',
|
||||||
author_email = 'code@fluxid.pl, urizieli@gmail.com',
|
author_email = 'code@fluxid.pl, urizieli@gmail.com',
|
||||||
description = 'Solution to synchronize playback of multiple MPlayer and MPC-HC instances over the network.',
|
description = 'Syncplay',
|
||||||
packages = find_packages(exclude=['venv']),
|
packages = find_packages(exclude=['venv']),
|
||||||
install_requires = ['Twisted>=11.1'],
|
install_requires = ['Twisted>=11.1'],
|
||||||
)
|
)
|
||||||
|
|||||||
@ -45,7 +45,7 @@ class SyncClientProtocol(CommandProtocol):
|
|||||||
print message
|
print message
|
||||||
self._syncplayClient.name = args[0]
|
self._syncplayClient.name = args[0]
|
||||||
self._syncplayClient.protocol.sender.send_list()
|
self._syncplayClient.protocol.sender.send_list()
|
||||||
self._syncplayClient.schedule_send_status()
|
self._syncplayClient.scheduleSendStatus()
|
||||||
|
|
||||||
@argumentCount(2, 3)
|
@argumentCount(2, 3)
|
||||||
def present(self, args):
|
def present(self, args):
|
||||||
@ -71,7 +71,7 @@ class SyncClientProtocol(CommandProtocol):
|
|||||||
|
|
||||||
counter, ctime, paused, position, name = args
|
counter, ctime, paused, position, name = args
|
||||||
|
|
||||||
self._syncplayClient.update_global_state(counter, ctime, paused, position, name)
|
self._syncplayClient.updateGlobalState(counter, ctime, paused, position, name)
|
||||||
|
|
||||||
@argumentCount(3)
|
@argumentCount(3)
|
||||||
def seek(self, args):
|
def seek(self, args):
|
||||||
@ -152,7 +152,7 @@ class SyncClientProtocol(CommandProtocol):
|
|||||||
def send_state(self, counter, ctime, paused, position):
|
def send_state(self, counter, ctime, paused, position):
|
||||||
self._protocol.sendMessage('state', counter, int(ctime*1000), ('paused' if paused else 'playing'), int(position*1000))
|
self._protocol.sendMessage('state', counter, int(ctime*1000), ('paused' if paused else 'playing'), int(position*1000))
|
||||||
|
|
||||||
def send_seek(self, counter, ctime, position):
|
def sendSeek(self, counter, ctime, position):
|
||||||
self._protocol.sendMessage('seek', counter, int(ctime*1000), int(position*1000))
|
self._protocol.sendMessage('seek', counter, int(ctime*1000), int(position*1000))
|
||||||
|
|
||||||
def send_room(self, where):
|
def send_room(self, where):
|
||||||
@ -246,7 +246,7 @@ class SyncplayClientManager(object):
|
|||||||
reactor.callLater(0.1, reactor.stop)
|
reactor.callLater(0.1, reactor.stop)
|
||||||
|
|
||||||
|
|
||||||
def get_player_position(self):
|
def getPlayerPosition(self):
|
||||||
if not self.last_player_update:
|
if not self.last_player_update:
|
||||||
return 0.0
|
return 0.0
|
||||||
position = self.player_position
|
position = self.player_position
|
||||||
@ -254,7 +254,7 @@ class SyncplayClientManager(object):
|
|||||||
position += time.time() - self.last_player_update
|
position += time.time() - self.last_player_update
|
||||||
return position
|
return position
|
||||||
|
|
||||||
def get_global_position(self):
|
def getGlobalPosition(self):
|
||||||
if not self.last_global_update:
|
if not self.last_global_update:
|
||||||
return 0.0
|
return 0.0
|
||||||
position = self.global_position
|
position = self.global_position
|
||||||
@ -263,12 +263,12 @@ class SyncplayClientManager(object):
|
|||||||
return position
|
return position
|
||||||
|
|
||||||
|
|
||||||
def init_player(self, player):
|
def initPlayer(self, player):
|
||||||
self.player = player
|
self.player = player
|
||||||
if self.last_global_update:
|
if self.last_global_update:
|
||||||
self.player.set_position(self.get_global_position())
|
self.player.set_position(self.getGlobalPosition())
|
||||||
self.player.set_paused(True)
|
self.player.set_paused(True)
|
||||||
self.schedule_ask_player()
|
self.scheduleAskPlayer()
|
||||||
|
|
||||||
def initProtocol(self, protocol):
|
def initProtocol(self, protocol):
|
||||||
self.protocol = protocol
|
self.protocol = protocol
|
||||||
@ -281,30 +281,30 @@ class SyncplayClientManager(object):
|
|||||||
self.protocol.drop()
|
self.protocol.drop()
|
||||||
self.protocol = None
|
self.protocol = None
|
||||||
|
|
||||||
def schedule_ask_player(self, when=0.2):
|
def scheduleAskPlayer(self, when=0.2):
|
||||||
if self.ask_delayed and self.ask_delayed.active():
|
if self.ask_delayed and self.ask_delayed.active():
|
||||||
self.ask_delayed.reset(when)
|
self.ask_delayed.reset(when)
|
||||||
else:
|
else:
|
||||||
self.ask_delayed = reactor.callLater(when, self.ask_player)
|
self.ask_delayed = reactor.callLater(when, self.askPlayer)
|
||||||
|
|
||||||
def ask_player(self):
|
def askPlayer(self):
|
||||||
if not self.running:
|
if not self.running:
|
||||||
return
|
return
|
||||||
if self.player:
|
if self.player:
|
||||||
self.status_ask_sent += 1
|
self.status_ask_sent += 1
|
||||||
self.player.ask_for_status()
|
self.player.ask_for_status()
|
||||||
self.schedule_ask_player()
|
self.scheduleAskPlayer()
|
||||||
|
|
||||||
def schedule_send_status(self, when=1):
|
def scheduleSendStatus(self, when=1):
|
||||||
if self.send_delayed and self.send_delayed.active():
|
if self.send_delayed and self.send_delayed.active():
|
||||||
self.send_delayed.reset(when)
|
self.send_delayed.reset(when)
|
||||||
else:
|
else:
|
||||||
self.send_delayed = reactor.callLater(when, self.send_status)
|
self.send_delayed = reactor.callLater(when, self.sendStatus)
|
||||||
|
|
||||||
def send_status(self, force = False):
|
def sendStatus(self, force = False):
|
||||||
if not (self.running and self.protocol):
|
if not (self.running and self.protocol):
|
||||||
return
|
return
|
||||||
self.schedule_send_status()
|
self.scheduleSendStatus()
|
||||||
if self.counter > self.counter_recv and not force:
|
if self.counter > self.counter_recv and not force:
|
||||||
return
|
return
|
||||||
self.counter += 1
|
self.counter += 1
|
||||||
@ -315,20 +315,20 @@ class SyncplayClientManager(object):
|
|||||||
if self.protocol:
|
if self.protocol:
|
||||||
self.protocol.sender.send_state(self.counter, curtime, self.player_paused, self.player_position)
|
self.protocol.sender.send_state(self.counter, curtime, self.player_paused, self.player_position)
|
||||||
|
|
||||||
def send_seek(self):
|
def sendSeek(self):
|
||||||
if not (self.running and self.protocol):
|
if not (self.running and self.protocol):
|
||||||
return
|
return
|
||||||
self.counter += 10
|
self.counter += 10
|
||||||
self.protocol.sender.send_seek(self.counter, time.time(), self.player_position)
|
self.protocol.sender.sendSeek(self.counter, time.time(), self.player_position)
|
||||||
message = self.name +' seeked to ' + format_time(self.player_position)
|
message = self.name +' seeked to ' + format_time(self.player_position)
|
||||||
print message
|
print message
|
||||||
self.player.display_message(message)
|
self.player.display_message(message)
|
||||||
|
|
||||||
def send_filename(self):
|
def sendFilename(self):
|
||||||
if self.protocol and self.player_filename:
|
if self.protocol and self.player_filename:
|
||||||
self.protocol.sender.send_playing(self.player_filename)
|
self.protocol.sender.send_playing(self.player_filename)
|
||||||
|
|
||||||
def __exectue_seek_cmd(self, seek_type, minutes, seconds):
|
def __exectueSeekCmd(self, seek_type, minutes, seconds):
|
||||||
self.player_position_before_last_seek = self.player_position
|
self.player_position_before_last_seek = self.player_position
|
||||||
if seek_type == 's':
|
if seek_type == 's':
|
||||||
seconds = int(seconds) if seconds <> None else 0
|
seconds = int(seconds) if seconds <> None else 0
|
||||||
@ -339,13 +339,13 @@ class SyncplayClientManager(object):
|
|||||||
seconds += int(minutes) * 60 if minutes <> None else 60
|
seconds += int(minutes) * 60 if minutes <> None else 60
|
||||||
self.player.set_position(self.player_position+seconds)
|
self.player.set_position(self.player_position+seconds)
|
||||||
|
|
||||||
def execute_command(self, data):
|
def executeCommand(self, data):
|
||||||
RE_SEEK = re.compile("^(s[+s]?) ?(-?\d+)?([^0-9](\d+))?$")
|
RE_SEEK = re.compile("^(s[+s]?) ?(-?\d+)?([^0-9](\d+))?$")
|
||||||
RE_ROOM = re.compile("^room( (\w+))?")
|
RE_ROOM = re.compile("^room( (\w+))?")
|
||||||
matched_seek = RE_SEEK.match(data)
|
matched_seek = RE_SEEK.match(data)
|
||||||
matched_room = RE_ROOM.match(data)
|
matched_room = RE_ROOM.match(data)
|
||||||
if matched_seek :
|
if matched_seek :
|
||||||
self.__exectue_seek_cmd(matched_seek.group(1), matched_seek.group(2), matched_seek.group(4))
|
self.__exectueSeekCmd(matched_seek.group(1), matched_seek.group(2), matched_seek.group(4))
|
||||||
elif matched_room:
|
elif matched_room:
|
||||||
room = matched_room.group(2)
|
room = matched_room.group(2)
|
||||||
if room == None:
|
if room == None:
|
||||||
@ -366,7 +366,7 @@ class SyncplayClientManager(object):
|
|||||||
print "\tp - toggle pause"
|
print "\tp - toggle pause"
|
||||||
print "\troom [room] - change room, if no supplied go to default"
|
print "\troom [room] - change room, if no supplied go to default"
|
||||||
|
|
||||||
def update_player_status(self, paused, position):
|
def updatePlayerStatus(self, paused, position):
|
||||||
self.status_ask_received += 1
|
self.status_ask_received += 1
|
||||||
if self.status_ask_received < self.status_ask_sent:
|
if self.status_ask_received < self.status_ask_sent:
|
||||||
return
|
return
|
||||||
@ -374,18 +374,18 @@ class SyncplayClientManager(object):
|
|||||||
self.player_paused = paused
|
self.player_paused = paused
|
||||||
self.player_position = position
|
self.player_position = position
|
||||||
self.last_player_update = time.time()
|
self.last_player_update = time.time()
|
||||||
diff = position - self.get_global_position()
|
diff = position - self.getGlobalPosition()
|
||||||
if old_paused and not paused:
|
if old_paused and not paused:
|
||||||
self.player_paused_at = None
|
self.player_paused_at = None
|
||||||
if old_paused != paused and self.global_paused != paused:
|
if old_paused != paused and self.global_paused != paused:
|
||||||
self.send_status(True)
|
self.sendStatus(True)
|
||||||
if paused:
|
if paused:
|
||||||
message = '%s paused' % self.name
|
message = '%s paused' % self.name
|
||||||
print message
|
print message
|
||||||
self.player.display_message(message)
|
self.player.display_message(message)
|
||||||
if(diff > 0):
|
if(diff > 0):
|
||||||
self.player.set_position(self.get_global_position())
|
self.player.set_position(self.getGlobalPosition())
|
||||||
self.ask_player()
|
self.askPlayer()
|
||||||
else:
|
else:
|
||||||
message = '%s unpaused' % self.name
|
message = '%s unpaused' % self.name
|
||||||
print message
|
print message
|
||||||
@ -402,19 +402,19 @@ class SyncplayClientManager(object):
|
|||||||
self.player.set_speed(1)
|
self.player.set_speed(1)
|
||||||
self.player_speed_fix = False
|
self.player_speed_fix = False
|
||||||
if abs(diff) > 8:# and not self.seek_sent_wait:
|
if abs(diff) > 8:# and not self.seek_sent_wait:
|
||||||
self.send_seek()
|
self.sendSeek()
|
||||||
self.seek_sent_wait = True
|
self.seek_sent_wait = True
|
||||||
if not paused and self.player_paused_at is not None and position >= self.player_paused_at:
|
if not paused and self.player_paused_at is not None and position >= self.player_paused_at:
|
||||||
#print 'Pausing %0.2fs after pause point' % (position - self.player_paused_at)
|
#print 'Pausing %0.2fs after pause point' % (position - self.player_paused_at)
|
||||||
self.player.set_paused(True)
|
self.player.set_paused(True)
|
||||||
self.ask_player()
|
self.askPlayer()
|
||||||
|
|
||||||
def update_filename(self, filename):
|
def updateFilename(self, filename):
|
||||||
filename = unicode(filename, errors='replace')
|
filename = unicode(filename, errors='replace')
|
||||||
self.player_filename = filename.encode('ascii','replace')
|
self.player_filename = filename.encode('ascii','replace')
|
||||||
self.send_filename()
|
self.sendFilename()
|
||||||
|
|
||||||
def update_global_state(self, counter, ctime, paused, position, name):
|
def updateGlobalState(self, counter, ctime, paused, position, name):
|
||||||
self.counter_recv = max(self.counter_recv, counter)
|
self.counter_recv = max(self.counter_recv, counter)
|
||||||
counter_valid = self.counter and counter >= self.counter
|
counter_valid = self.counter and counter >= self.counter
|
||||||
|
|
||||||
@ -443,7 +443,7 @@ class SyncplayClientManager(object):
|
|||||||
changed = True
|
changed = True
|
||||||
|
|
||||||
if counter_valid:
|
if counter_valid:
|
||||||
diff = self.get_player_position() - position
|
diff = self.getPlayerPosition() - position
|
||||||
if abs(diff) > 4:
|
if abs(diff) > 4:
|
||||||
self.player.set_position(position)
|
self.player.set_position(position)
|
||||||
#self.player.set_paused(True)
|
#self.player.set_paused(True)
|
||||||
@ -467,15 +467,15 @@ class SyncplayClientManager(object):
|
|||||||
print message
|
print message
|
||||||
self.player.display_message(message)
|
self.player.display_message(message)
|
||||||
if(diff > 0):
|
if(diff > 0):
|
||||||
self.player.set_position(self.get_global_position())
|
self.player.set_position(self.getGlobalPosition())
|
||||||
self.ask_player()
|
self.askPlayer()
|
||||||
if diff < 0:
|
if diff < 0:
|
||||||
self.player.set_paused(True)
|
self.player.set_paused(True)
|
||||||
self.global_noted_pause_change = paused
|
self.global_noted_pause_change = paused
|
||||||
changed = True
|
changed = True
|
||||||
|
|
||||||
if changed:
|
if changed:
|
||||||
self.ask_player()
|
self.askPlayer()
|
||||||
|
|
||||||
|
|
||||||
def seek(self, ctime, position, who):
|
def seek(self, ctime, position, who):
|
||||||
@ -486,7 +486,7 @@ class SyncplayClientManager(object):
|
|||||||
if self.player:
|
if self.player:
|
||||||
self.player_position_before_last_seek = self.player_position
|
self.player_position_before_last_seek = self.player_position
|
||||||
self.player.set_position(position)
|
self.player.set_position(position)
|
||||||
self.ask_player()
|
self.askPlayer()
|
||||||
message = who + ' seeked to ' + format_time(position)
|
message = who + ' seeked to ' + format_time(position)
|
||||||
print message
|
print message
|
||||||
self.player.display_message(message)
|
self.player.display_message(message)
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import win32con, win32api, win32gui, ctypes, ctypes.wintypes
|
|||||||
|
|
||||||
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
|
||||||
'''
|
'''
|
||||||
List of callbacks that can be set
|
List of callbacks that can be set
|
||||||
on_connected (0 args)
|
on_connected (0 args)
|
||||||
@ -15,8 +16,7 @@ class MPC_API:
|
|||||||
on_update_playstate (playstate)
|
on_update_playstate (playstate)
|
||||||
on_file_ready (filename)
|
on_file_ready (filename)
|
||||||
custom_handler (cmd, value)
|
custom_handler (cmd, value)
|
||||||
'''
|
'''
|
||||||
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
|
||||||
@ -50,7 +50,6 @@ class MPC_API:
|
|||||||
|
|
||||||
'''
|
'''
|
||||||
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
|
|
||||||
'''
|
'''
|
||||||
def is_api_ready(self):
|
def is_api_ready(self):
|
||||||
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
|
||||||
@ -59,28 +58,28 @@ class MPC_API:
|
|||||||
|
|
||||||
'''
|
'''
|
||||||
Checks if file is loaded in player
|
Checks if file is loaded in player
|
||||||
Throws MPC_API.NoSlaveDetectedException if mpc window is not found
|
|
||||||
'''
|
'''
|
||||||
def is_file_ready(self):
|
def is_file_ready(self):
|
||||||
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)
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Opens a file given in an argument in player
|
Opens a file given in an argument in player
|
||||||
Throws MPC_API.NoSlaveDetectedException if mpc window is not found
|
|
||||||
'''
|
'''
|
||||||
def open_file(self, file_path):
|
def open_file(self, file_path):
|
||||||
self.__listener.SendCommand(MPC_API_COMMANDS.CMD_OPENFILE, file_path)
|
self.__listener.SendCommand(MPC_API_COMMANDS.CMD_OPENFILE, file_path)
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Is player paused (Stop is considered pause)
|
Is player paused (Stop is considered pause)
|
||||||
Throws MPC_API.NoSlaveDetectedException if mpc window is not found
|
|
||||||
'''
|
'''
|
||||||
def is_paused(self):
|
def is_paused(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)
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Pause playing file
|
Pause playing file
|
||||||
Throws MPC_API.NoSlaveDetectedException if mpc window is not found
|
|
||||||
'''
|
'''
|
||||||
def pause(self):
|
def pause(self):
|
||||||
if(not self.is_file_ready()): raise MPC_API.PlayerNotReadyException("Playstate change on no file")
|
if(not self.is_file_ready()): raise MPC_API.PlayerNotReadyException("Playstate change on no file")
|
||||||
@ -88,7 +87,7 @@ class MPC_API:
|
|||||||
self.playpause()
|
self.playpause()
|
||||||
'''
|
'''
|
||||||
Play paused file
|
Play paused file
|
||||||
Throws MPC_API.NoSlaveDetectedException if mpc window is not found
|
|
||||||
'''
|
'''
|
||||||
def unpause(self):
|
def unpause(self):
|
||||||
if(not self.is_file_ready()): raise MPC_API.PlayerNotReadyException("Playstate change on no file")
|
if(not self.is_file_ready()): raise MPC_API.PlayerNotReadyException("Playstate change on no file")
|
||||||
@ -96,7 +95,7 @@ class MPC_API:
|
|||||||
self.playpause()
|
self.playpause()
|
||||||
'''
|
'''
|
||||||
Toggle play/pause
|
Toggle play/pause
|
||||||
Throws MPC_API.NoSlaveDetectedException if mpc window is not found
|
|
||||||
'''
|
'''
|
||||||
def playpause(self):
|
def playpause(self):
|
||||||
if(not self.is_file_ready()): raise MPC_API.PlayerNotReadyException("Playstate change on no file")
|
if(not self.is_file_ready()): raise MPC_API.PlayerNotReadyException("Playstate change on no file")
|
||||||
@ -112,7 +111,7 @@ class MPC_API:
|
|||||||
'''
|
'''
|
||||||
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
|
||||||
developers should rather rely on that rather than on a return value
|
developers should rather rely on that rather than on a return value
|
||||||
Throws MPC_API.NoSlaveDetectedException if mpc window is not found
|
|
||||||
'''
|
'''
|
||||||
def ask_for_current_position(self):
|
def ask_for_current_position(self):
|
||||||
if(not self.is_file_ready()):
|
if(not self.is_file_ready()):
|
||||||
@ -125,7 +124,7 @@ class MPC_API:
|
|||||||
return self.lastfileposition
|
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
|
|
||||||
'''
|
'''
|
||||||
def seek(self, position):
|
def seek(self, position):
|
||||||
self.__locks.seek.clear()
|
self.__locks.seek.clear()
|
||||||
@ -136,7 +135,7 @@ class MPC_API:
|
|||||||
@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
|
||||||
@param DurationMs: Duration of osd display, defaults to 3000
|
@param DurationMs: Duration of osd display, defaults to 3000
|
||||||
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):
|
||||||
class __OSDDATASTRUCT(ctypes.Structure):
|
class __OSDDATASTRUCT(ctypes.Structure):
|
||||||
@ -155,7 +154,7 @@ class MPC_API:
|
|||||||
Send raw cmd and value to mpc
|
Send raw cmd and value to mpc
|
||||||
Commands are available in MPC_API_COMMANDS class
|
Commands are available in MPC_API_COMMANDS class
|
||||||
Value has to be either ctype.Structure or unicode string
|
Value has to be either ctype.Structure or unicode string
|
||||||
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.__listener.SendCommand(cmd, value)
|
self.__listener.SendCommand(cmd, value)
|
||||||
@ -178,6 +177,7 @@ class MPC_API:
|
|||||||
|
|
||||||
elif(cmd == MPC_API_COMMANDS.CMD_STATE):
|
elif(cmd == MPC_API_COMMANDS.CMD_STATE):
|
||||||
self.loadstate = int(value)
|
self.loadstate = int(value)
|
||||||
|
if(self.callbacks.on_fileStateChange): thread.start_new_thread(self.callbacks.on_fileStateChange, (self.loadstate,))
|
||||||
|
|
||||||
elif(cmd == MPC_API_COMMANDS.CMD_PLAYMODE):
|
elif(cmd == MPC_API_COMMANDS.CMD_PLAYMODE):
|
||||||
self.playstate = int(value)
|
self.playstate = int(value)
|
||||||
@ -188,7 +188,6 @@ class MPC_API:
|
|||||||
if(self.callbacks.on_update_filename): thread.start_new_thread(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): thread.start_new_thread(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)
|
||||||
@ -211,7 +210,6 @@ class MPC_API:
|
|||||||
def __init__(self, message):
|
def __init__(self, message):
|
||||||
Exception.__init__(self, message)
|
Exception.__init__(self, message)
|
||||||
|
|
||||||
|
|
||||||
class __CALLBACKS:
|
class __CALLBACKS:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.on_connected = None
|
self.on_connected = None
|
||||||
@ -220,7 +218,7 @@ class MPC_API:
|
|||||||
self.on_update_file_duration = None
|
self.on_update_file_duration = None
|
||||||
self.on_update_position = None
|
self.on_update_position = None
|
||||||
self.on_update_playstate = None
|
self.on_update_playstate = None
|
||||||
self.on_file_ready = None
|
self.on_fileStateChange = None
|
||||||
self.custom_handler = None
|
self.custom_handler = None
|
||||||
self.on_mpc_closed = None
|
self.on_mpc_closed = None
|
||||||
|
|
||||||
@ -295,12 +293,11 @@ class MPC_API:
|
|||||||
|
|
||||||
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 ">>> 0x%X" % 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.__mpc_api.handle_command(pCDS.contents.dwData, ctypes.wstring_at(pCDS.contents.lpData))
|
self.__mpc_api.handle_command(pCDS.contents.dwData, ctypes.wstring_at(pCDS.contents.lpData))
|
||||||
|
|
||||||
|
|
||||||
def SendCommand(self, cmd, message = u''):
|
def SendCommand(self, cmd, message = u''):
|
||||||
# print "<<< 0x%X" % int(cmd), message
|
#print "API:\t<out\t 0x%X\t" % int(cmd), message
|
||||||
if not win32gui.IsWindow(self.mpc_handle):
|
if not win32gui.IsWindow(self.mpc_handle):
|
||||||
raise MPC_API.NoSlaveDetectedException("MPC Slave Window not detected")
|
raise MPC_API.NoSlaveDetectedException("MPC Slave Window not detected")
|
||||||
cs = self.__COPYDATASTRUCT()
|
cs = self.__COPYDATASTRUCT()
|
||||||
@ -316,7 +313,7 @@ class MPC_API:
|
|||||||
cs.cbData = ctypes.sizeof(message)
|
cs.cbData = ctypes.sizeof(message)
|
||||||
ptr= ctypes.addressof(cs)
|
ptr= ctypes.addressof(cs)
|
||||||
win32api.SendMessage(self.mpc_handle, win32con.WM_COPYDATA, self.hwnd, ptr)
|
win32api.SendMessage(self.mpc_handle, win32con.WM_COPYDATA, self.hwnd, ptr)
|
||||||
|
|
||||||
class __COPYDATASTRUCT(ctypes.Structure):
|
class __COPYDATASTRUCT(ctypes.Structure):
|
||||||
_fields_ = [
|
_fields_ = [
|
||||||
('dwData', ctypes.wintypes.LPARAM),
|
('dwData', ctypes.wintypes.LPARAM),
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
from ..mpc_api import MPC_API
|
from ..mpc_api import MPC_API
|
||||||
import time
|
import time
|
||||||
|
import threading
|
||||||
|
|
||||||
class MPCHCAPIPlayer(object):
|
class MPCHCAPIPlayer(object):
|
||||||
def __init__(self, manager):
|
def __init__(self, manager):
|
||||||
@ -9,17 +10,25 @@ class MPCHCAPIPlayer(object):
|
|||||||
self.mpc_api = MPC_API()
|
self.mpc_api = MPC_API()
|
||||||
|
|
||||||
self.pinged = False
|
self.pinged = False
|
||||||
self.tmp_filename = None
|
|
||||||
self.tmp_position = None
|
self.mpc_api.callbacks.on_update_filename = lambda _: 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.mpc_api.callbacks.on_mpc_closed = lambda: self.mpc_error("MPC closed")
|
||||||
|
|
||||||
self.semaphore_filename = False
|
self.mpc_api.callbacks.on_fileStateChange = self.lockAsking
|
||||||
|
self.mpc_api.callbacks.on_update_playstate = self.unlockAsking
|
||||||
|
|
||||||
|
self.askSemaphore = False
|
||||||
|
self.askLock = threading.RLock()
|
||||||
|
|
||||||
def drop(self):
|
def drop(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def lockAsking(self, state):
|
||||||
|
self.askSemaphore = True
|
||||||
|
|
||||||
|
def unlockAsking(self, state):
|
||||||
|
self.askSemaphore = False
|
||||||
|
|
||||||
def set_speed(self, value):
|
def set_speed(self, value):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -32,9 +41,10 @@ class MPCHCAPIPlayer(object):
|
|||||||
return
|
return
|
||||||
|
|
||||||
def make_ping(self):
|
def make_ping(self):
|
||||||
self.mpc_api.callbacks.on_file_ready = None
|
|
||||||
self.test_mpc_ready()
|
self.test_mpc_ready()
|
||||||
self._syncplayClient.init_player(self)
|
self.mpc_api.callbacks.on_update_filename = self.handle_updated_filename
|
||||||
|
self._syncplayClient.initPlayer(self)
|
||||||
|
self.handle_updated_filename(self.mpc_api.fileplaying)
|
||||||
self.pinged = True
|
self.pinged = True
|
||||||
self.ask_for_status()
|
self.ask_for_status()
|
||||||
|
|
||||||
@ -66,55 +76,58 @@ class MPCHCAPIPlayer(object):
|
|||||||
except Exception, err:
|
except Exception, err:
|
||||||
self.mpc_error(err)
|
self.mpc_error(err)
|
||||||
|
|
||||||
def ask_for_status(self):
|
def __askForPositionUntilPlayerReady(self):
|
||||||
position = self.tmp_position if self.tmp_position else 0
|
|
||||||
paused = None
|
|
||||||
try:
|
try:
|
||||||
if(self.mpc_api.is_file_ready() and not self.semaphore_filename):
|
return self.mpc_api.ask_for_current_position()
|
||||||
try:
|
except MPC_API.PlayerNotReadyException:
|
||||||
position = self.mpc_api.ask_for_current_position()
|
time.sleep(0.1)
|
||||||
except MPC_API.PlayerNotReadyException:
|
return self.__askForPositionUntilPlayerReady()
|
||||||
time.sleep(0.1)
|
|
||||||
self.ask_for_status()
|
def ask_for_status(self):
|
||||||
return
|
try:
|
||||||
if(self.tmp_filename <> self.mpc_api.fileplaying):
|
self.askLock.acquire()
|
||||||
self.handle_updated_filename(self.mpc_api.fileplaying)
|
if(self.mpc_api.is_file_ready() and not self.askSemaphore):
|
||||||
return
|
position = self.__askForPositionUntilPlayerReady()
|
||||||
paused = self.mpc_api.is_paused()
|
paused = self.mpc_api.is_paused()
|
||||||
position = float(position)
|
position = float(position)
|
||||||
self.tmp_position = position
|
if(not self.askSemaphore):
|
||||||
self._syncplayClient.update_player_status(paused, position)
|
self._syncplayClient.updatePlayerStatus(paused, position)
|
||||||
else:
|
return
|
||||||
self._syncplayClient.update_player_status(True, self._syncplayClient.get_global_position())
|
self._syncplayClient.updatePlayerStatus(True, self._syncplayClient.getGlobalPosition())
|
||||||
except Exception, err:
|
except Exception, err:
|
||||||
self.mpc_error(err)
|
self.mpc_error(err)
|
||||||
|
finally:
|
||||||
def __force_pause(self, filename, position):
|
self.askLock.release()
|
||||||
self.set_paused(True)
|
|
||||||
|
def __pauseChangeCheckLoop(self, i, changeFrom):
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
if (not self.mpc_api.is_paused()):
|
if(i < 10):
|
||||||
self.__set_up_newly_opened_file(filename, position)
|
if(self.mpc_api.is_paused() <> changeFrom):
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
self.__pauseChangeCheckLoop(i+1, True)
|
||||||
|
|
||||||
|
def __force_pause(self):
|
||||||
|
self.__pauseChangeCheckLoop(0, True)
|
||||||
|
self.set_paused(True)
|
||||||
|
|
||||||
def __set_up_newly_opened_file(self, filename, position):
|
def __set_up_newly_opened_file(self, filename, position):
|
||||||
self.test_mpc_ready()
|
|
||||||
try:
|
try:
|
||||||
|
self.__force_pause()
|
||||||
self.mpc_api.seek(position)
|
self.mpc_api.seek(position)
|
||||||
except MPC_API.PlayerNotReadyException:
|
except MPC_API.PlayerNotReadyException:
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
self.__set_up_newly_opened_file(filename, position)
|
self.__set_up_newly_opened_file(filename, position)
|
||||||
self.__force_pause(filename, position)
|
|
||||||
|
|
||||||
def handle_updated_filename(self, filename):
|
def handle_updated_filename(self, filename):
|
||||||
position = self._syncplayClient.get_global_position()
|
try:
|
||||||
if(self.semaphore_filename):
|
self.askLock.acquire()
|
||||||
self._syncplayClient.update_player_status(True, position)
|
position = self._syncplayClient.getGlobalPosition()
|
||||||
return
|
self.__set_up_newly_opened_file(filename, position)
|
||||||
self.semaphore_filename = True
|
self._syncplayClient.updateFilename(str(filename))
|
||||||
self.__set_up_newly_opened_file(filename, position)
|
finally:
|
||||||
self.tmp_filename = filename
|
self.askLock.release()
|
||||||
self._syncplayClient.update_filename(str(self.tmp_filename))
|
|
||||||
self._syncplayClient.update_player_status(True, position)
|
|
||||||
self.semaphore_filename = False
|
|
||||||
|
|
||||||
def mpc_error(self, err=""):
|
def mpc_error(self, err=""):
|
||||||
print "ERROR:", str(err) + ',', "desu"
|
print "ERROR:", str(err) + ',', "desu"
|
||||||
|
|||||||
@ -106,8 +106,8 @@ class MplayerProtocol(LineProcessProtocol):
|
|||||||
self.send_get_property('filename')
|
self.send_get_property('filename')
|
||||||
|
|
||||||
def mplayer_answer_filename(self, value):
|
def mplayer_answer_filename(self, value):
|
||||||
self._syncplayClient.init_player(self)
|
self._syncplayClient.initPlayer(self)
|
||||||
self._syncplayClient.update_filename(value)
|
self._syncplayClient.updateFilename(value)
|
||||||
|
|
||||||
|
|
||||||
def set_paused(self, value):
|
def set_paused(self, value):
|
||||||
@ -130,7 +130,7 @@ class MplayerProtocol(LineProcessProtocol):
|
|||||||
|
|
||||||
def mplayer_answer_time_pos(self, value):
|
def mplayer_answer_time_pos(self, value):
|
||||||
value = float(value)
|
value = float(value)
|
||||||
self._syncplayClient.update_player_status(self.tmp_paused, value)
|
self._syncplayClient.updatePlayerStatus(self.tmp_paused, value)
|
||||||
|
|
||||||
|
|
||||||
def set_speed(self, value):
|
def set_speed(self, value):
|
||||||
|
|||||||
@ -29,7 +29,7 @@ class ConsoleUI(threading.Thread):
|
|||||||
self.PromptResult = data
|
self.PromptResult = data
|
||||||
self.promptMode.set()
|
self.promptMode.set()
|
||||||
elif(self._syncplayClient):
|
elif(self._syncplayClient):
|
||||||
self._syncplayClient.execute_command(data)
|
self._syncplayClient.executeCommand(data)
|
||||||
except:
|
except:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|||||||
@ -75,7 +75,7 @@ def stdin_thread(manager):
|
|||||||
data = os.read(fd, 1024)
|
data = os.read(fd, 1024)
|
||||||
if not data:
|
if not data:
|
||||||
break
|
break
|
||||||
manager.execute_command(data.rstrip('\n\r'))
|
manager.executeCommand(data.rstrip('\n\r'))
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -97,7 +97,7 @@ class ConfigurationGetter(object):
|
|||||||
raise Exception('Working dir not found')
|
raise Exception('Working dir not found')
|
||||||
|
|
||||||
def _prepareArgParser(self):
|
def _prepareArgParser(self):
|
||||||
self._parser = argparse.ArgumentParser(description='Syncplay',
|
self._parser = argparse.ArgumentParser(description='Solution to synchronize playback of multiple MPlayer and MPC-HC instances over the network.',
|
||||||
epilog='If no options supplied _config values will be used')
|
epilog='If no options supplied _config values will be used')
|
||||||
self._parser.add_argument('--no-gui', action='store_true', help='show no GUI')
|
self._parser.add_argument('--no-gui', action='store_true', help='show no GUI')
|
||||||
self._parser.add_argument('--host', metavar='hostname', type=str, help='server\'s address')
|
self._parser.add_argument('--host', metavar='hostname', type=str, help='server\'s address')
|
||||||
@ -126,6 +126,7 @@ class ConfigurationGetter(object):
|
|||||||
self._config.write(configfile)
|
self._config.write(configfile)
|
||||||
|
|
||||||
def _setUpValuesToSave(self, section_name):
|
def _setUpValuesToSave(self, section_name):
|
||||||
|
self._splitPortAndHost()
|
||||||
self._config.set(section_name, 'host', self._args.host)
|
self._config.set(section_name, 'host', self._args.host)
|
||||||
self._config.set(section_name, 'name', self._args.name)
|
self._config.set(section_name, 'name', self._args.name)
|
||||||
|
|
||||||
@ -146,11 +147,12 @@ class ConfigurationGetter(object):
|
|||||||
self._args.name = self._config.get(section_name, 'name')
|
self._args.name = self._config.get(section_name, 'name')
|
||||||
|
|
||||||
def _splitPortAndHost(self):
|
def _splitPortAndHost(self):
|
||||||
if ':' in self._args.host:
|
if(self._args.host):
|
||||||
self._args.host, port = self._args.host.split(':', 1)
|
if ':' in self._args.host:
|
||||||
self._args.port = int(port)
|
self._args.host, port = self._args.host.split(':', 1)
|
||||||
else:
|
self._args.port = int(port)
|
||||||
self._args.port = 8999
|
else:
|
||||||
|
self._args.port = 8999
|
||||||
|
|
||||||
def prepareClientConfiguration(self):
|
def prepareClientConfiguration(self):
|
||||||
self._findWorkingDirectory()
|
self._findWorkingDirectory()
|
||||||
|
|||||||
@ -7,7 +7,8 @@ from syncplay import utils
|
|||||||
class SyncplayMPC:
|
class SyncplayMPC:
|
||||||
def runClient(self):
|
def runClient(self):
|
||||||
self._prepareArguments()
|
self._prepareArguments()
|
||||||
self.interface = ui.getUi(graphical = not self.args.no_gui)
|
# self.interface = ui.getUi(graphical = not self.args.no_gui)
|
||||||
|
self.interface = ui.getUi(graphical = False) #TODO: add gui
|
||||||
self._promptForMissingArguments()
|
self._promptForMissingArguments()
|
||||||
syncplayClient = client.SyncplayClientManager(self.args.name, lambda m: mpc.run_mpc(m, self.args.mpc_path, self.args.file, self.args._args), self.interface, self.args.debug)
|
syncplayClient = client.SyncplayClientManager(self.args.name, lambda m: mpc.run_mpc(m, self.args.mpc_path, self.args.file, self.args._args), self.interface, self.args.debug)
|
||||||
self.interface.addClient(syncplayClient)
|
self.interface.addClient(syncplayClient)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user