Fixed offsets

Renamed util for utils, added proper time parsing
This commit is contained in:
Uriziel 2012-12-24 19:13:33 +01:00
parent 71ab3b386f
commit 694747397c
4 changed files with 106 additions and 52 deletions

View File

@ -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)

View File

@ -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:

View File

@ -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)

View File

@ -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)