Fixed offsets
Renamed util for utils, added proper time parsing
This commit is contained in:
parent
71ab3b386f
commit
694747397c
@ -5,6 +5,7 @@ import time
|
||||
from twisted.internet.protocol import ClientFactory
|
||||
from twisted.internet import reactor, task
|
||||
from syncplay.protocols import SyncClientProtocol
|
||||
from syncplay import utils
|
||||
|
||||
class SyncClientFactory(ClientFactory):
|
||||
def __init__(self, client, retry = 10):
|
||||
@ -78,6 +79,7 @@ class SyncplayClient(object):
|
||||
self._lastGlobalUpdate = None
|
||||
self._globalPosition = 0.0
|
||||
self._globalPaused = 0.0
|
||||
self._userOffset = 0.0
|
||||
self._speedChanged = False
|
||||
|
||||
def initProtocol(self, protocol):
|
||||
@ -119,7 +121,8 @@ class SyncplayClient(object):
|
||||
return pauseChange, seeked
|
||||
|
||||
def updatePlayerStatus(self, paused, position):
|
||||
pauseChange, seeked = self._determinePlayerStateChange(paused, position)
|
||||
position -= self.getUserOffset()
|
||||
pauseChange, seeked = self._determinePlayerStateChange(paused, position)
|
||||
self._playerPosition = position
|
||||
self._playerPaused = paused
|
||||
if(self._lastGlobalUpdate):
|
||||
@ -139,13 +142,13 @@ class SyncplayClient(object):
|
||||
return None, None, None, None
|
||||
|
||||
def _initPlayerState(self, position, paused):
|
||||
self._player.setPosition(position)
|
||||
self.setPosition(position)
|
||||
self._player.setPaused(paused)
|
||||
madeChangeOnPlayer = True
|
||||
return madeChangeOnPlayer
|
||||
|
||||
def _rewindPlayerDueToTimeDifference(self, position, setBy):
|
||||
self._player.setPosition(position)
|
||||
self.setPosition(position)
|
||||
message = "Rewinded due to time difference with <{}>".format(setBy)
|
||||
self.ui.showMessage(message)
|
||||
madeChangeOnPlayer = True
|
||||
@ -160,7 +163,7 @@ class SyncplayClient(object):
|
||||
|
||||
def _serverPaused(self, setBy, diff):
|
||||
if (diff > 0):
|
||||
self._player.setPosition(self.getGlobalPosition())
|
||||
self.setPosition(self.getGlobalPosition())
|
||||
self._player.setPaused(True)
|
||||
madeChangeOnPlayer = True
|
||||
message = '<{}> paused'.format(setBy)
|
||||
@ -170,11 +173,11 @@ class SyncplayClient(object):
|
||||
def _serverSeeked(self, position, setBy):
|
||||
if(self.getUsername() <> setBy):
|
||||
self.playerPositionBeforeLastSeek = self.getPlayerPosition()
|
||||
self._player.setPosition(position)
|
||||
self.setPosition(position)
|
||||
madeChangeOnPlayer = True
|
||||
else:
|
||||
madeChangeOnPlayer = False
|
||||
message = '<{}> jumped from {} to {}'.format(setBy, self.ui.formatTime(self.playerPositionBeforeLastSeek), self.ui.formatTime(position))
|
||||
message = '<{}> jumped from {} to {}'.format(setBy, utils.formatTime(self.playerPositionBeforeLastSeek), utils.formatTime(position))
|
||||
self.ui.showMessage(message)
|
||||
return madeChangeOnPlayer
|
||||
|
||||
@ -214,12 +217,22 @@ class SyncplayClient(object):
|
||||
self.__getUserlistOnLogon = False
|
||||
self.getUserList()
|
||||
madeChangeOnPlayer = False
|
||||
|
||||
if(not paused):
|
||||
position += latency
|
||||
if(self._player):
|
||||
madeChangeOnPlayer = self._changePlayerStateAccordingToGlobalState(position, paused, doSeek, setBy)
|
||||
if(madeChangeOnPlayer):
|
||||
self.askPlayer()
|
||||
|
||||
def getUserOffset(self):
|
||||
return self._userOffset
|
||||
|
||||
def setUserOffset(self, time):
|
||||
self._userOffset = time
|
||||
message = "Current offset: {} seconds".format(self._userOffset)
|
||||
self.setPosition(self.getGlobalPosition())
|
||||
self.ui.showMessage(message)
|
||||
|
||||
def getPlayerPosition(self):
|
||||
if(not self._lastPlayerUpdate):
|
||||
@ -291,7 +304,10 @@ class SyncplayClient(object):
|
||||
return self._serverPassword
|
||||
|
||||
def setPosition(self, position):
|
||||
position += self.getUserOffset()
|
||||
if(self._player):
|
||||
if(position < 0):
|
||||
position = 0
|
||||
self._player.setPosition(position)
|
||||
|
||||
def setPaused(self, paused):
|
||||
@ -360,7 +376,7 @@ class SyncplayUserlist(object):
|
||||
message = "<{}> has joined the room: '{}'".format(username, room)
|
||||
self.ui.showMessage(message)
|
||||
elif (room and file_ and username != self.currentUser.username):
|
||||
duration = self.ui.formatTime(file_['duration'])
|
||||
duration = utils.formatTime(file_['duration'])
|
||||
message = "<{}> is playing '{}' ({})".format(username, file_['name'], duration)
|
||||
if(self.currentUser.room <> room or self.currentUser.username == username):
|
||||
message += " in room: '{}'".format(room)
|
||||
@ -411,8 +427,8 @@ class SyncplayUserlist(object):
|
||||
self.addUser(username, room, file_)
|
||||
|
||||
def __addUserWithFileToList(self, rooms, user):
|
||||
currentPosition = self.ui.formatTime(user.lastPosition)
|
||||
file_key = '\'{}\' ({}/{})'.format(user.file['name'], currentPosition, self.ui.formatTime(user.file['duration']))
|
||||
currentPosition = utils.formatTime(user.lastPosition)
|
||||
file_key = '\'{}\' ({}/{})'.format(user.file['name'], currentPosition, utils.formatTime(user.file['duration']))
|
||||
if (not rooms[user.room].has_key(file_key)):
|
||||
rooms[user.room][file_key] = {}
|
||||
rooms[user.room][file_key][user.username] = user
|
||||
@ -492,19 +508,3 @@ class UiManager(object):
|
||||
def promptFor(self, prompt):
|
||||
return self.__ui.promptFor(prompt)
|
||||
|
||||
def formatTime(self, timeInSeconds):
|
||||
timeInSeconds = round(timeInSeconds)
|
||||
weeks = timeInSeconds // 604800
|
||||
days = (timeInSeconds % 604800) // 86400
|
||||
hours = (timeInSeconds % 86400) // 3600
|
||||
minutes = (timeInSeconds % 3600) // 60
|
||||
seconds = timeInSeconds % 60
|
||||
if(weeks > 0):
|
||||
return '{0:.0f}w, {1:.0f}d, {2:02.0f}:{3:02.0f}:{4:02.0f}'.format(weeks, days, hours, minutes, seconds)
|
||||
elif(days > 0):
|
||||
return '{0:.0f}d, {1:02.0f}:{2:02.0f}:{3:02.0f}'.format(days, hours, minutes, seconds)
|
||||
elif(hours > 0):
|
||||
return '{0:02.0f}:{1:02.0f}:{2:02.0f}'.format(hours, minutes, seconds)
|
||||
else:
|
||||
return '{0:02.0f}:{1:02.0f}'.format(minutes, seconds)
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ import win32con, win32api, win32gui, ctypes, ctypes.wintypes #@UnresolvedImport
|
||||
from functools import wraps
|
||||
from syncplay.players.basePlayer import BasePlayer
|
||||
import re
|
||||
from syncplay.util import retry
|
||||
from syncplay.utils import retry
|
||||
|
||||
|
||||
class MpcHcApi:
|
||||
|
||||
@ -4,6 +4,7 @@ import time
|
||||
import syncplay
|
||||
import os
|
||||
import re
|
||||
from syncplay import utils
|
||||
|
||||
class ConsoleUI(threading.Thread):
|
||||
def __init__(self):
|
||||
@ -48,26 +49,52 @@ class ConsoleUI(threading.Thread):
|
||||
def showErrorMessage(self, message):
|
||||
print("ERROR:\t" + message)
|
||||
|
||||
def __doSeek(self, m):
|
||||
if (m.group(4)):
|
||||
t = int(m.group(5)) * 60 + int(m.group(6))
|
||||
else:
|
||||
t = int(m.group(2))
|
||||
def _extractRegexSign(self, m):
|
||||
if(m.group(1)):
|
||||
if(m.group(1) == "-"):
|
||||
sign = -1
|
||||
return -1
|
||||
else:
|
||||
sign = 1
|
||||
t = self._syncplayClient.getGlobalPosition() + sign * t
|
||||
self._syncplayClient.setPosition(t)
|
||||
return 1
|
||||
else:
|
||||
return None
|
||||
|
||||
def _tryAdvancedCommands(self, data):
|
||||
o = re.match(r"^(?:o|offset)\ ([+-])?\ ?(.+)$", data)
|
||||
s = re.match(r"^(?:s|seek)?\ ?([+-])?\ ?(.+)$", data) #careful! s will match o as well
|
||||
if(o):
|
||||
sign = self._extractRegexSign(o)
|
||||
t = utils.parseTime(o.group(2))
|
||||
if(not t):
|
||||
return
|
||||
if(sign):
|
||||
t = self._syncplayClient.getUserOffset() + sign * t
|
||||
self._syncplayClient.setUserOffset(t)
|
||||
return True
|
||||
elif s:
|
||||
sign = self._extractRegexSign(s)
|
||||
t = utils.parseTime(s.group(2))
|
||||
if(t is None):
|
||||
return
|
||||
if(sign):
|
||||
t = self._syncplayClient.getGlobalPosition() + sign * t
|
||||
self._syncplayClient.setPosition(t)
|
||||
return True
|
||||
return False
|
||||
|
||||
def _executeCommand(self, data):
|
||||
m = re.match(r"^s? ?([+-])? ?((\d+)|((\d+)\D(\d+)))$", data)
|
||||
r = re.match(r"^(r|room)( (.+))?$", data)
|
||||
if(m):
|
||||
self.__doSeek(m)
|
||||
elif r:
|
||||
room = r.group(3)
|
||||
command = re.match(r"^(.+)(?:\ (.+))?", data)
|
||||
if(not command):
|
||||
return
|
||||
if(command.group(1) in ["u", "undo", "revert"]):
|
||||
tmp_pos = self._syncplayClient.getPlayerPosition()
|
||||
self._syncplayClient.setPosition(self._syncplayClient.playerPositionBeforeLastSeek)
|
||||
self._syncplayClient.playerPositionBeforeLastSeek = tmp_pos
|
||||
elif (command.group(1) in ["l", "list", "users"]):
|
||||
self._syncplayClient.getUserList()
|
||||
elif (command.group(1) in ["p", "play", "pause"]):
|
||||
self._syncplayClient.setPaused(not self._syncplayClient.getPlayerPaused())
|
||||
elif (command.group(1) in ["r", "room"]):
|
||||
room = command.group(1)
|
||||
if room == None:
|
||||
if self._syncplayClient.userlist.currentUser.file:
|
||||
room = self._syncplayClient.userlist.currentUser.file["name"]
|
||||
@ -75,16 +102,10 @@ class ConsoleUI(threading.Thread):
|
||||
room = self._syncplayClient.defaultRoom
|
||||
self._syncplayClient.setRoom(room)
|
||||
self._syncplayClient.sendRoom()
|
||||
elif data == "u":
|
||||
tmp_pos = self._syncplayClient.getPlayerPosition()
|
||||
self._syncplayClient.setPosition(self._syncplayClient.playerPositionBeforeLastSeek)
|
||||
self._syncplayClient.playerPositionBeforeLastSeek = tmp_pos
|
||||
elif data == "l":
|
||||
self._syncplayClient.getUserList()
|
||||
elif data == "p":
|
||||
self._syncplayClient.setPaused(not self._syncplayClient.getPlayerPaused())
|
||||
else:
|
||||
if data not in ['help', 'h', '?', '/?', '\?']:
|
||||
if(self._tryAdvancedCommands(data)):
|
||||
return
|
||||
if (command.group(1) not in ['help', 'h', '?', '/?', '\?']):
|
||||
self.showMessage("Unrecognized command")
|
||||
self.showMessage("Available commands:", True)
|
||||
self.showMessage("\tr [name] - change room", True)
|
||||
@ -95,4 +116,4 @@ class ConsoleUI(threading.Thread):
|
||||
self.showMessage("\th - this help", True)
|
||||
self.showMessage("Syncplay version: {}".format(syncplay.version), True)
|
||||
self.showMessage("More info available at: {}".format(syncplay.projectURL), True)
|
||||
|
||||
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
import time
|
||||
import re
|
||||
import datetime
|
||||
|
||||
def retry(ExceptionToCheck, tries=4, delay=3, backoff=2, logger=None):
|
||||
"""Retry calling the decorated function using an exponential backoff.
|
||||
@ -39,4 +41,35 @@ def retry(ExceptionToCheck, tries=4, delay=3, backoff=2, logger=None):
|
||||
return f(*args, **kwargs)
|
||||
return
|
||||
return f_retry # true decorator
|
||||
return deco_retry
|
||||
return deco_retry
|
||||
|
||||
def parseTime(timeStr):
|
||||
regex = re.compile(r'(:?(?:(?P<hours>\d+?)[^\d\.])?(?:(?P<minutes>\d+?))?[^\d\.])?(?P<seconds>\d+?)(?:\.(?P<miliseconds>\d+?))?$')
|
||||
parts = regex.match(timeStr)
|
||||
if not parts:
|
||||
return
|
||||
parts = parts.groupdict()
|
||||
time_params = {}
|
||||
for (name, param) in parts.iteritems():
|
||||
if param:
|
||||
if(name == "miliseconds"):
|
||||
time_params["microseconds"] = int(param) * 1000
|
||||
else:
|
||||
time_params[name] = int(param)
|
||||
return datetime.timedelta(**time_params).total_seconds()
|
||||
|
||||
def formatTime(timeInSeconds):
|
||||
timeInSeconds = round(timeInSeconds)
|
||||
weeks = timeInSeconds // 604800
|
||||
days = (timeInSeconds % 604800) // 86400
|
||||
hours = (timeInSeconds % 86400) // 3600
|
||||
minutes = (timeInSeconds % 3600) // 60
|
||||
seconds = timeInSeconds % 60
|
||||
if(weeks > 0):
|
||||
return '{0:.0f}w, {1:.0f}d, {2:02.0f}:{3:02.0f}:{4:02.0f}'.format(weeks, days, hours, minutes, seconds)
|
||||
elif(days > 0):
|
||||
return '{0:.0f}d, {1:02.0f}:{2:02.0f}:{3:02.0f}'.format(days, hours, minutes, seconds)
|
||||
elif(hours > 0):
|
||||
return '{0:02.0f}:{1:02.0f}:{2:02.0f}'.format(hours, minutes, seconds)
|
||||
else:
|
||||
return '{0:02.0f}:{1:02.0f}'.format(minutes, seconds)
|
||||
Loading…
x
Reference in New Issue
Block a user