|
|
|
@ -1,4 +1,3 @@
|
|
|
|
#coding:utf8
|
|
|
|
|
|
|
|
import hashlib
|
|
|
|
import hashlib
|
|
|
|
import os.path
|
|
|
|
import os.path
|
|
|
|
import time
|
|
|
|
import time
|
|
|
|
@ -9,8 +8,9 @@ from syncplay.protocols import SyncClientProtocol
|
|
|
|
from syncplay import utils, constants
|
|
|
|
from syncplay import utils, constants
|
|
|
|
from syncplay.messages import getMessage
|
|
|
|
from syncplay.messages import getMessage
|
|
|
|
import threading
|
|
|
|
import threading
|
|
|
|
from syncplay.constants import PRIVACY_SENDHASHED_MODE, PRIVACY_DONTSEND_MODE,\
|
|
|
|
from syncplay.constants import PRIVACY_SENDHASHED_MODE, PRIVACY_DONTSEND_MODE, \
|
|
|
|
PRIVACY_HIDDENFILENAME, FILENAME_STRIP_REGEX
|
|
|
|
PRIVACY_HIDDENFILENAME, FILENAME_STRIP_REGEX
|
|
|
|
|
|
|
|
import collections
|
|
|
|
# <MAL DISABLE>
|
|
|
|
# <MAL DISABLE>
|
|
|
|
libMal = None
|
|
|
|
libMal = None
|
|
|
|
'''try:
|
|
|
|
'''try:
|
|
|
|
@ -19,13 +19,14 @@ except ImportError:
|
|
|
|
libMal = None
|
|
|
|
libMal = None
|
|
|
|
'''
|
|
|
|
'''
|
|
|
|
# </MAL DISABLE>
|
|
|
|
# </MAL DISABLE>
|
|
|
|
|
|
|
|
|
|
|
|
class SyncClientFactory(ClientFactory):
|
|
|
|
class SyncClientFactory(ClientFactory):
|
|
|
|
def __init__(self, client, retry = constants.RECONNECT_RETRIES):
|
|
|
|
def __init__(self, client, retry=constants.RECONNECT_RETRIES):
|
|
|
|
self._client = client
|
|
|
|
self._client = client
|
|
|
|
self.retry = retry
|
|
|
|
self.retry = retry
|
|
|
|
self._timesTried = 0
|
|
|
|
self._timesTried = 0
|
|
|
|
self.reconnecting = False
|
|
|
|
self.reconnecting = False
|
|
|
|
|
|
|
|
|
|
|
|
def buildProtocol(self, addr):
|
|
|
|
def buildProtocol(self, addr):
|
|
|
|
self._timesTried = 0
|
|
|
|
self._timesTried = 0
|
|
|
|
return SyncClientProtocol(self._client)
|
|
|
|
return SyncClientProtocol(self._client)
|
|
|
|
@ -42,7 +43,7 @@ class SyncClientFactory(ClientFactory):
|
|
|
|
self._timesTried += 1
|
|
|
|
self._timesTried += 1
|
|
|
|
self._client.ui.showMessage(getMessage("en", "reconnection-attempt-notification"))
|
|
|
|
self._client.ui.showMessage(getMessage("en", "reconnection-attempt-notification"))
|
|
|
|
self.reconnecting = True
|
|
|
|
self.reconnecting = True
|
|
|
|
reactor.callLater(0.1*(2**self._timesTried), connector.connect)
|
|
|
|
reactor.callLater(0.1 * (2 ** self._timesTried), connector.connect)
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
message = getMessage("en", "disconnection-notification")
|
|
|
|
message = getMessage("en", "disconnection-notification")
|
|
|
|
self._client.ui.showErrorMessage(message)
|
|
|
|
self._client.ui.showErrorMessage(message)
|
|
|
|
@ -52,13 +53,13 @@ class SyncClientFactory(ClientFactory):
|
|
|
|
self._client.ui.showErrorMessage(getMessage("en", "connection-failed-notification"))
|
|
|
|
self._client.ui.showErrorMessage(getMessage("en", "connection-failed-notification"))
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
self.clientConnectionLost(connector, reason)
|
|
|
|
self.clientConnectionLost(connector, reason)
|
|
|
|
|
|
|
|
|
|
|
|
def resetRetrying(self):
|
|
|
|
def resetRetrying(self):
|
|
|
|
self._timesTried = 0
|
|
|
|
self._timesTried = 0
|
|
|
|
|
|
|
|
|
|
|
|
def stopRetrying(self):
|
|
|
|
def stopRetrying(self):
|
|
|
|
self._timesTried = self.retry
|
|
|
|
self._timesTried = self.retry
|
|
|
|
|
|
|
|
|
|
|
|
class SyncplayClient(object):
|
|
|
|
class SyncplayClient(object):
|
|
|
|
def __init__(self, playerClass, ui, config):
|
|
|
|
def __init__(self, playerClass, ui, config):
|
|
|
|
self.protocolFactory = SyncClientFactory(self)
|
|
|
|
self.protocolFactory = SyncClientFactory(self)
|
|
|
|
@ -68,7 +69,7 @@ class SyncplayClient(object):
|
|
|
|
self._player = None
|
|
|
|
self._player = None
|
|
|
|
self.givenmalprivacywarning = False
|
|
|
|
self.givenmalprivacywarning = False
|
|
|
|
if(config['room'] == None or config['room'] == ''):
|
|
|
|
if(config['room'] == None or config['room'] == ''):
|
|
|
|
config['room'] = config['name'] # ticket #58
|
|
|
|
config['room'] = config['name'] # ticket #58
|
|
|
|
self.defaultRoom = config['room']
|
|
|
|
self.defaultRoom = config['room']
|
|
|
|
self.playerPositionBeforeLastSeek = 0.0
|
|
|
|
self.playerPositionBeforeLastSeek = 0.0
|
|
|
|
self.setUsername(config['name'])
|
|
|
|
self.setUsername(config['name'])
|
|
|
|
@ -82,39 +83,39 @@ class SyncplayClient(object):
|
|
|
|
self.__getUserlistOnLogon = False
|
|
|
|
self.__getUserlistOnLogon = False
|
|
|
|
self._playerClass = playerClass
|
|
|
|
self._playerClass = playerClass
|
|
|
|
self._config = config
|
|
|
|
self._config = config
|
|
|
|
|
|
|
|
|
|
|
|
self._running = False
|
|
|
|
self._running = False
|
|
|
|
self._askPlayerTimer = None
|
|
|
|
self._askPlayerTimer = None
|
|
|
|
|
|
|
|
|
|
|
|
self._lastPlayerUpdate = None
|
|
|
|
self._lastPlayerUpdate = None
|
|
|
|
self._playerPosition = 0.0
|
|
|
|
self._playerPosition = 0.0
|
|
|
|
self._playerPaused = True
|
|
|
|
self._playerPaused = True
|
|
|
|
|
|
|
|
|
|
|
|
self._lastGlobalUpdate = None
|
|
|
|
self._lastGlobalUpdate = None
|
|
|
|
self._globalPosition = 0.0
|
|
|
|
self._globalPosition = 0.0
|
|
|
|
self._globalPaused = 0.0
|
|
|
|
self._globalPaused = 0.0
|
|
|
|
self._userOffset = 0.0
|
|
|
|
self._userOffset = 0.0
|
|
|
|
self._speedChanged = False
|
|
|
|
self._speedChanged = False
|
|
|
|
|
|
|
|
|
|
|
|
self._warnings = self._WarningManager(self._player, self.userlist, self.ui)
|
|
|
|
self._warnings = self._WarningManager(self._player, self.userlist, self.ui)
|
|
|
|
self._malUpdater = MalUpdater(config["malUsername"], config["malPassword"], self.ui)
|
|
|
|
self._malUpdater = MalUpdater(config["malUsername"], config["malPassword"], self.ui)
|
|
|
|
|
|
|
|
|
|
|
|
def initProtocol(self, protocol):
|
|
|
|
def initProtocol(self, protocol):
|
|
|
|
self._protocol = protocol
|
|
|
|
self._protocol = protocol
|
|
|
|
|
|
|
|
|
|
|
|
def destroyProtocol(self):
|
|
|
|
def destroyProtocol(self):
|
|
|
|
if(self._protocol):
|
|
|
|
if(self._protocol):
|
|
|
|
self._protocol.drop()
|
|
|
|
self._protocol.drop()
|
|
|
|
self._protocol = None
|
|
|
|
self._protocol = None
|
|
|
|
|
|
|
|
|
|
|
|
def initPlayer(self, player):
|
|
|
|
def initPlayer(self, player):
|
|
|
|
self._player = player
|
|
|
|
self._player = player
|
|
|
|
self.scheduleAskPlayer()
|
|
|
|
self.scheduleAskPlayer()
|
|
|
|
|
|
|
|
|
|
|
|
def scheduleAskPlayer(self, when=constants.PLAYER_ASK_DELAY):
|
|
|
|
def scheduleAskPlayer(self, when=constants.PLAYER_ASK_DELAY):
|
|
|
|
self._askPlayerTimer = task.LoopingCall(self.askPlayer)
|
|
|
|
self._askPlayerTimer = task.LoopingCall(self.askPlayer)
|
|
|
|
self._askPlayerTimer.start(when)
|
|
|
|
self._askPlayerTimer.start(when)
|
|
|
|
|
|
|
|
|
|
|
|
def askPlayer(self):
|
|
|
|
def askPlayer(self):
|
|
|
|
if(not self._running):
|
|
|
|
if(not self._running):
|
|
|
|
return
|
|
|
|
return
|
|
|
|
@ -135,7 +136,7 @@ class SyncplayClient(object):
|
|
|
|
_playerDiff = abs(self.getPlayerPosition() - position)
|
|
|
|
_playerDiff = abs(self.getPlayerPosition() - position)
|
|
|
|
_globalDiff = abs(self.getGlobalPosition() - position)
|
|
|
|
_globalDiff = abs(self.getGlobalPosition() - position)
|
|
|
|
seeked = _playerDiff > constants.SEEK_THRESHOLD and _globalDiff > constants.SEEK_THRESHOLD
|
|
|
|
seeked = _playerDiff > constants.SEEK_THRESHOLD and _globalDiff > constants.SEEK_THRESHOLD
|
|
|
|
return pauseChange, seeked
|
|
|
|
return pauseChange, seeked
|
|
|
|
|
|
|
|
|
|
|
|
def updatePlayerStatus(self, paused, position):
|
|
|
|
def updatePlayerStatus(self, paused, position):
|
|
|
|
position -= self.getUserOffset()
|
|
|
|
position -= self.getUserOffset()
|
|
|
|
@ -147,7 +148,7 @@ class SyncplayClient(object):
|
|
|
|
if((pauseChange or seeked) and self._protocol):
|
|
|
|
if((pauseChange or seeked) and self._protocol):
|
|
|
|
if(seeked):
|
|
|
|
if(seeked):
|
|
|
|
self.playerPositionBeforeLastSeek = self.getGlobalPosition()
|
|
|
|
self.playerPositionBeforeLastSeek = self.getGlobalPosition()
|
|
|
|
self._protocol.sendState(self.getPlayerPosition(), self.getPlayerPaused(), seeked, None, True)
|
|
|
|
self._protocol.sendState(self.getPlayerPosition(), self.getPlayerPaused(), seeked, None, True)
|
|
|
|
|
|
|
|
|
|
|
|
def getLocalState(self):
|
|
|
|
def getLocalState(self):
|
|
|
|
paused = self.getPlayerPaused()
|
|
|
|
paused = self.getPlayerPaused()
|
|
|
|
@ -157,7 +158,7 @@ class SyncplayClient(object):
|
|
|
|
return position, paused, _, pauseChange
|
|
|
|
return position, paused, _, pauseChange
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
return None, None, None, None
|
|
|
|
return None, None, None, None
|
|
|
|
|
|
|
|
|
|
|
|
def _initPlayerState(self, position, paused):
|
|
|
|
def _initPlayerState(self, position, paused):
|
|
|
|
if(self.userlist.currentUser.file):
|
|
|
|
if(self.userlist.currentUser.file):
|
|
|
|
self.setPosition(position)
|
|
|
|
self.setPosition(position)
|
|
|
|
@ -246,10 +247,10 @@ class SyncplayClient(object):
|
|
|
|
if(madeChangeOnPlayer):
|
|
|
|
if(madeChangeOnPlayer):
|
|
|
|
self.askPlayer()
|
|
|
|
self.askPlayer()
|
|
|
|
self._executePlaystateHooks(position, paused, doSeek, setBy, messageAge)
|
|
|
|
self._executePlaystateHooks(position, paused, doSeek, setBy, messageAge)
|
|
|
|
|
|
|
|
|
|
|
|
def getUserOffset(self):
|
|
|
|
def getUserOffset(self):
|
|
|
|
return self._userOffset
|
|
|
|
return self._userOffset
|
|
|
|
|
|
|
|
|
|
|
|
def setUserOffset(self, time):
|
|
|
|
def setUserOffset(self, time):
|
|
|
|
self._userOffset = time
|
|
|
|
self._userOffset = time
|
|
|
|
self.setPosition(self.getGlobalPosition())
|
|
|
|
self.setPosition(self.getGlobalPosition())
|
|
|
|
@ -273,7 +274,7 @@ class SyncplayClient(object):
|
|
|
|
position = self._playerPosition
|
|
|
|
position = self._playerPosition
|
|
|
|
if(not self._playerPaused):
|
|
|
|
if(not self._playerPaused):
|
|
|
|
diff = time.time() - self._lastPlayerUpdate
|
|
|
|
diff = time.time() - self._lastPlayerUpdate
|
|
|
|
position += diff
|
|
|
|
position += diff
|
|
|
|
return position
|
|
|
|
return position
|
|
|
|
|
|
|
|
|
|
|
|
def getPlayerPaused(self):
|
|
|
|
def getPlayerPaused(self):
|
|
|
|
@ -282,8 +283,8 @@ class SyncplayClient(object):
|
|
|
|
return self.getGlobalPaused()
|
|
|
|
return self.getGlobalPaused()
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
return True
|
|
|
|
return True
|
|
|
|
return self._playerPaused
|
|
|
|
return self._playerPaused
|
|
|
|
|
|
|
|
|
|
|
|
def getGlobalPosition(self):
|
|
|
|
def getGlobalPosition(self):
|
|
|
|
if not self._lastGlobalUpdate:
|
|
|
|
if not self._lastGlobalUpdate:
|
|
|
|
return 0.0
|
|
|
|
return 0.0
|
|
|
|
@ -291,18 +292,18 @@ class SyncplayClient(object):
|
|
|
|
if not self._globalPaused:
|
|
|
|
if not self._globalPaused:
|
|
|
|
position += time.time() - self._lastGlobalUpdate
|
|
|
|
position += time.time() - self._lastGlobalUpdate
|
|
|
|
return position
|
|
|
|
return position
|
|
|
|
|
|
|
|
|
|
|
|
def getGlobalPaused(self):
|
|
|
|
def getGlobalPaused(self):
|
|
|
|
if(not self._lastGlobalUpdate):
|
|
|
|
if(not self._lastGlobalUpdate):
|
|
|
|
return True
|
|
|
|
return True
|
|
|
|
return self._globalPaused
|
|
|
|
return self._globalPaused
|
|
|
|
|
|
|
|
|
|
|
|
def updateFile(self, filename, duration, path):
|
|
|
|
def updateFile(self, filename, duration, path):
|
|
|
|
if not path:
|
|
|
|
if not path:
|
|
|
|
return
|
|
|
|
return
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
size = os.path.getsize(path)
|
|
|
|
size = os.path.getsize(path)
|
|
|
|
except OSError: #file not accessible (stream?)
|
|
|
|
except OSError: # file not accessible (stream?)
|
|
|
|
size = 0
|
|
|
|
size = 0
|
|
|
|
rawfilename = filename
|
|
|
|
rawfilename = filename
|
|
|
|
filename, size = self.__executePrivacySettings(filename, size)
|
|
|
|
filename, size = self.__executePrivacySettings(filename, size)
|
|
|
|
@ -313,11 +314,11 @@ class SyncplayClient(object):
|
|
|
|
message = getMessage("en", "mal-noprivacy-notification")
|
|
|
|
message = getMessage("en", "mal-noprivacy-notification")
|
|
|
|
self.ui.showErrorMessage(message)
|
|
|
|
self.ui.showErrorMessage(message)
|
|
|
|
self.givenmalprivacywarning = True
|
|
|
|
self.givenmalprivacywarning = True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __executePrivacySettings(self, filename, size):
|
|
|
|
def __executePrivacySettings(self, filename, size):
|
|
|
|
if (self._config['filenamePrivacyMode'] == PRIVACY_SENDHASHED_MODE):
|
|
|
|
if (self._config['filenamePrivacyMode'] == PRIVACY_SENDHASHED_MODE):
|
|
|
|
filename = utils.hashFilename(filename)
|
|
|
|
filename = utils.hashFilename(filename)
|
|
|
|
elif (self._config['filenamePrivacyMode'] == PRIVACY_DONTSEND_MODE):
|
|
|
|
elif (self._config['filenamePrivacyMode'] == PRIVACY_DONTSEND_MODE):
|
|
|
|
filename = PRIVACY_HIDDENFILENAME
|
|
|
|
filename = PRIVACY_HIDDENFILENAME
|
|
|
|
if (self._config['filesizePrivacyMode'] == PRIVACY_SENDHASHED_MODE):
|
|
|
|
if (self._config['filesizePrivacyMode'] == PRIVACY_SENDHASHED_MODE):
|
|
|
|
@ -333,44 +334,44 @@ class SyncplayClient(object):
|
|
|
|
|
|
|
|
|
|
|
|
def setUsername(self, username):
|
|
|
|
def setUsername(self, username):
|
|
|
|
self.userlist.currentUser.username = username
|
|
|
|
self.userlist.currentUser.username = username
|
|
|
|
|
|
|
|
|
|
|
|
def getUsername(self):
|
|
|
|
def getUsername(self):
|
|
|
|
return self.userlist.currentUser.username
|
|
|
|
return self.userlist.currentUser.username
|
|
|
|
|
|
|
|
|
|
|
|
def setRoom(self, roomName):
|
|
|
|
def setRoom(self, roomName):
|
|
|
|
self.userlist.currentUser.room = roomName
|
|
|
|
self.userlist.currentUser.room = roomName
|
|
|
|
|
|
|
|
|
|
|
|
def sendRoom(self):
|
|
|
|
def sendRoom(self):
|
|
|
|
room = self.userlist.currentUser.room
|
|
|
|
room = self.userlist.currentUser.room
|
|
|
|
if(self._protocol and self._protocol.logged and room):
|
|
|
|
if(self._protocol and self._protocol.logged and room):
|
|
|
|
self._protocol.sendRoomSetting(room)
|
|
|
|
self._protocol.sendRoomSetting(room)
|
|
|
|
self.getUserList()
|
|
|
|
self.getUserList()
|
|
|
|
|
|
|
|
|
|
|
|
def getRoom(self):
|
|
|
|
def getRoom(self):
|
|
|
|
return self.userlist.currentUser.room
|
|
|
|
return self.userlist.currentUser.room
|
|
|
|
|
|
|
|
|
|
|
|
def getUserList(self):
|
|
|
|
def getUserList(self):
|
|
|
|
if(self._protocol and self._protocol.logged):
|
|
|
|
if(self._protocol and self._protocol.logged):
|
|
|
|
self._protocol.sendList()
|
|
|
|
self._protocol.sendList()
|
|
|
|
|
|
|
|
|
|
|
|
def showUserList(self):
|
|
|
|
def showUserList(self):
|
|
|
|
self.userlist.showUserList()
|
|
|
|
self.userlist.showUserList()
|
|
|
|
|
|
|
|
|
|
|
|
def getPassword(self):
|
|
|
|
def getPassword(self):
|
|
|
|
return self._serverPassword
|
|
|
|
return self._serverPassword
|
|
|
|
|
|
|
|
|
|
|
|
def setPosition(self, position):
|
|
|
|
def setPosition(self, position):
|
|
|
|
position += self.getUserOffset()
|
|
|
|
position += self.getUserOffset()
|
|
|
|
if(self._player and self.userlist.currentUser.file):
|
|
|
|
if(self._player and self.userlist.currentUser.file):
|
|
|
|
if(position < 0):
|
|
|
|
if(position < 0):
|
|
|
|
position = 0
|
|
|
|
position = 0
|
|
|
|
self._protocol.sendState(self.getPlayerPosition(), self.getPlayerPaused(), True, None, True)
|
|
|
|
self._protocol.sendState(self.getPlayerPosition(), self.getPlayerPaused(), True, None, True)
|
|
|
|
self._player.setPosition(position)
|
|
|
|
self._player.setPosition(position)
|
|
|
|
|
|
|
|
|
|
|
|
def setPaused(self, paused):
|
|
|
|
def setPaused(self, paused):
|
|
|
|
if(self._player and self.userlist.currentUser.file):
|
|
|
|
if(self._player and self.userlist.currentUser.file):
|
|
|
|
self._player.setPaused(paused)
|
|
|
|
self._player.setPaused(paused)
|
|
|
|
|
|
|
|
|
|
|
|
def start(self, host, port):
|
|
|
|
def start(self, host, port):
|
|
|
|
if self._running:
|
|
|
|
if self._running:
|
|
|
|
return
|
|
|
|
return
|
|
|
|
@ -382,7 +383,7 @@ class SyncplayClient(object):
|
|
|
|
reactor.connectTCP(host, port, self.protocolFactory)
|
|
|
|
reactor.connectTCP(host, port, self.protocolFactory)
|
|
|
|
reactor.run()
|
|
|
|
reactor.run()
|
|
|
|
|
|
|
|
|
|
|
|
def stop(self, promptForAction = False):
|
|
|
|
def stop(self, promptForAction=False):
|
|
|
|
if not self._running:
|
|
|
|
if not self._running:
|
|
|
|
return
|
|
|
|
return
|
|
|
|
self._running = False
|
|
|
|
self._running = False
|
|
|
|
@ -415,7 +416,7 @@ class SyncplayClient(object):
|
|
|
|
def checkWarnings(self):
|
|
|
|
def checkWarnings(self):
|
|
|
|
self._checkIfYouReAloneInTheRoom()
|
|
|
|
self._checkIfYouReAloneInTheRoom()
|
|
|
|
self._checkRoomForSameFiles()
|
|
|
|
self._checkRoomForSameFiles()
|
|
|
|
|
|
|
|
|
|
|
|
def _checkRoomForSameFiles(self):
|
|
|
|
def _checkRoomForSameFiles(self):
|
|
|
|
if (not self._userlist.areAllFilesInRoomSame()):
|
|
|
|
if (not self._userlist.areAllFilesInRoomSame()):
|
|
|
|
self._ui.showMessage(getMessage("en", "room-files-not-same"), True)
|
|
|
|
self._ui.showMessage(getMessage("en", "room-files-not-same"), True)
|
|
|
|
@ -423,7 +424,7 @@ class SyncplayClient(object):
|
|
|
|
self._warnings["room-files-not-same"]['timer'].start(constants.WARNING_OSD_MESSAGES_LOOP_INTERVAL, True)
|
|
|
|
self._warnings["room-files-not-same"]['timer'].start(constants.WARNING_OSD_MESSAGES_LOOP_INTERVAL, True)
|
|
|
|
elif(self._warnings["room-files-not-same"]['timer'].running):
|
|
|
|
elif(self._warnings["room-files-not-same"]['timer'].running):
|
|
|
|
self._warnings["room-files-not-same"]['timer'].stop()
|
|
|
|
self._warnings["room-files-not-same"]['timer'].stop()
|
|
|
|
|
|
|
|
|
|
|
|
def _checkIfYouReAloneInTheRoom(self):
|
|
|
|
def _checkIfYouReAloneInTheRoom(self):
|
|
|
|
if (self._userlist.areYouAloneInRoom()):
|
|
|
|
if (self._userlist.areYouAloneInRoom()):
|
|
|
|
self._ui.showMessage(getMessage("en", "alone-in-the-room"), True)
|
|
|
|
self._ui.showMessage(getMessage("en", "alone-in-the-room"), True)
|
|
|
|
@ -431,24 +432,24 @@ class SyncplayClient(object):
|
|
|
|
self._warnings["alone-in-the-room"]['timer'].start(constants.WARNING_OSD_MESSAGES_LOOP_INTERVAL, True)
|
|
|
|
self._warnings["alone-in-the-room"]['timer'].start(constants.WARNING_OSD_MESSAGES_LOOP_INTERVAL, True)
|
|
|
|
elif(self._warnings["alone-in-the-room"]['timer'].running):
|
|
|
|
elif(self._warnings["alone-in-the-room"]['timer'].running):
|
|
|
|
self._warnings["alone-in-the-room"]['timer'].stop()
|
|
|
|
self._warnings["alone-in-the-room"]['timer'].stop()
|
|
|
|
|
|
|
|
|
|
|
|
def __displayMessageOnOSD(self, warningName):
|
|
|
|
def __displayMessageOnOSD(self, warningName):
|
|
|
|
if (constants.OSD_WARNING_MESSAGE_DURATION > self._warnings[warningName]["displayedFor"]):
|
|
|
|
if (constants.OSD_WARNING_MESSAGE_DURATION > self._warnings[warningName]["displayedFor"]):
|
|
|
|
self._ui.showOSDMessage(getMessage("en", warningName ), constants.WARNING_OSD_MESSAGES_LOOP_INTERVAL)
|
|
|
|
self._ui.showOSDMessage(getMessage("en", warningName), constants.WARNING_OSD_MESSAGES_LOOP_INTERVAL)
|
|
|
|
self._warnings[warningName]["displayedFor"] += constants.WARNING_OSD_MESSAGES_LOOP_INTERVAL
|
|
|
|
self._warnings[warningName]["displayedFor"] += constants.WARNING_OSD_MESSAGES_LOOP_INTERVAL
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
self._warnings[warningName]["displayedFor"] = 0
|
|
|
|
self._warnings[warningName]["displayedFor"] = 0
|
|
|
|
self._warnings[warningName]["timer"].stop()
|
|
|
|
self._warnings[warningName]["timer"].stop()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SyncplayUser(object):
|
|
|
|
class SyncplayUser(object):
|
|
|
|
def __init__(self, username = None, room = None, file_ = None, position = 0):
|
|
|
|
def __init__(self, username=None, room=None, file_=None, position=0):
|
|
|
|
self.username = username
|
|
|
|
self.username = username
|
|
|
|
self.room = room
|
|
|
|
self.room = room
|
|
|
|
self.file = file_
|
|
|
|
self.file = file_
|
|
|
|
self.lastPosition = position
|
|
|
|
self.lastPosition = position
|
|
|
|
|
|
|
|
|
|
|
|
def setFile(self, filename, duration, size):
|
|
|
|
def setFile(self, filename, duration, size):
|
|
|
|
file_ = {
|
|
|
|
file_ = {
|
|
|
|
"name": filename,
|
|
|
|
"name": filename,
|
|
|
|
@ -456,19 +457,24 @@ class SyncplayUser(object):
|
|
|
|
"size":size
|
|
|
|
"size":size
|
|
|
|
}
|
|
|
|
}
|
|
|
|
self.file = file_
|
|
|
|
self.file = file_
|
|
|
|
|
|
|
|
|
|
|
|
def isFileSame(self, file_):
|
|
|
|
def isFileSame(self, file_):
|
|
|
|
if(not self.file):
|
|
|
|
if(not self.file):
|
|
|
|
return False
|
|
|
|
return False
|
|
|
|
sameName = utils.sameFilename(self.file['name'], file_['name'])
|
|
|
|
sameName = utils.sameFilename(self.file['name'], file_['name'])
|
|
|
|
sameSize = utils.sameFilesize(self.file['size'], file_['size'])
|
|
|
|
sameSize = utils.sameFilesize(self.file['size'], file_['size'])
|
|
|
|
sameDuration = utils.sameFileduration(self.file['duration'], file_['duration'])
|
|
|
|
sameDuration = utils.sameFileduration(self.file['duration'], file_['duration'])
|
|
|
|
return sameName and sameSize and sameDuration
|
|
|
|
return sameName and sameSize and sameDuration
|
|
|
|
|
|
|
|
|
|
|
|
def __lt__(self, other):
|
|
|
|
def __lt__(self, other):
|
|
|
|
return self.username < other.username
|
|
|
|
return self.username.lower() < other.username.lower()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __repr__(self, *args, **kwargs):
|
|
|
|
|
|
|
|
if(self.file):
|
|
|
|
|
|
|
|
return "{}: {} ({}, {})".format(self.username, self.file['name'], self.file['duration'], self.file['size'])
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
return "{}".format(self.username)
|
|
|
|
|
|
|
|
|
|
|
|
class MalUpdater(object):
|
|
|
|
class MalUpdater(object):
|
|
|
|
def __init__(self, username, password, ui):
|
|
|
|
def __init__(self, username, password, ui):
|
|
|
|
self._filePlayingFor = 0.0
|
|
|
|
self._filePlayingFor = 0.0
|
|
|
|
@ -499,7 +505,7 @@ class MalUpdater(object):
|
|
|
|
self._filename = filename
|
|
|
|
self._filename = filename
|
|
|
|
self._filePlayingFor = 0.0
|
|
|
|
self._filePlayingFor = 0.0
|
|
|
|
self._lastHookUpdate = None
|
|
|
|
self._lastHookUpdate = None
|
|
|
|
|
|
|
|
|
|
|
|
def _updateMal(self):
|
|
|
|
def _updateMal(self):
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
self._fileDuration = 0 # Disable playingHook
|
|
|
|
self._fileDuration = 0 # Disable playingHook
|
|
|
|
@ -509,13 +515,13 @@ class MalUpdater(object):
|
|
|
|
if(len(results) > 0):
|
|
|
|
if(len(results) > 0):
|
|
|
|
result = results[0]
|
|
|
|
result = results[0]
|
|
|
|
message = "Updating MAL with: \"{}\", episode: {}".format(result.mainTitle, result.episodeBeingWatched)
|
|
|
|
message = "Updating MAL with: \"{}\", episode: {}".format(result.mainTitle, result.episodeBeingWatched)
|
|
|
|
reactor.callFromThread(self._ui.showMessage,(message),)
|
|
|
|
reactor.callFromThread(self._ui.showMessage, (message),)
|
|
|
|
options = {"tags": ["syncplay"]}
|
|
|
|
options = {"tags": ["syncplay"]}
|
|
|
|
manager.updateEntryOnMal(result, options)
|
|
|
|
manager.updateEntryOnMal(result, options)
|
|
|
|
self._filename = "" # Make sure no updates will be performed until switch
|
|
|
|
self._filename = "" # Make sure no updates will be performed until switch
|
|
|
|
except:
|
|
|
|
except:
|
|
|
|
reactor.callFromThread(self._ui.showMessage, ("MAL Update failure"),)
|
|
|
|
reactor.callFromThread(self._ui.showMessage, ("MAL Update failure"),)
|
|
|
|
|
|
|
|
|
|
|
|
class SyncplayUserlist(object):
|
|
|
|
class SyncplayUserlist(object):
|
|
|
|
def __init__(self, ui, client):
|
|
|
|
def __init__(self, ui, client):
|
|
|
|
self.currentUser = SyncplayUser()
|
|
|
|
self.currentUser = SyncplayUser()
|
|
|
|
@ -542,7 +548,7 @@ class SyncplayUserlist(object):
|
|
|
|
differentSize = not utils.sameFilesize(self.currentUser.file['size'], file_['size'])
|
|
|
|
differentSize = not utils.sameFilesize(self.currentUser.file['size'], file_['size'])
|
|
|
|
differentDuration = not utils.sameFileduration(self.currentUser.file['duration'], file_['duration'])
|
|
|
|
differentDuration = not utils.sameFileduration(self.currentUser.file['duration'], file_['duration'])
|
|
|
|
if(differentName):
|
|
|
|
if(differentName):
|
|
|
|
differences.append("filename")
|
|
|
|
differences.append("filename")
|
|
|
|
if(differentSize):
|
|
|
|
if(differentSize):
|
|
|
|
differences.append("size")
|
|
|
|
differences.append("size")
|
|
|
|
if(differentDuration):
|
|
|
|
if(differentDuration):
|
|
|
|
@ -550,7 +556,7 @@ class SyncplayUserlist(object):
|
|
|
|
message = getMessage("en", "file-differences-notification") + ", ".join(differences)
|
|
|
|
message = getMessage("en", "file-differences-notification") + ", ".join(differences)
|
|
|
|
self.ui.showMessage(message)
|
|
|
|
self.ui.showMessage(message)
|
|
|
|
|
|
|
|
|
|
|
|
def addUser(self, username, room, file_, position = 0, noMessage = False):
|
|
|
|
def addUser(self, username, room, file_, position=0, noMessage=False):
|
|
|
|
if(username == self.currentUser.username):
|
|
|
|
if(username == self.currentUser.username):
|
|
|
|
self.currentUser.lastPosition = position
|
|
|
|
self.currentUser.lastPosition = position
|
|
|
|
return
|
|
|
|
return
|
|
|
|
@ -559,14 +565,14 @@ class SyncplayUserlist(object):
|
|
|
|
if(not noMessage):
|
|
|
|
if(not noMessage):
|
|
|
|
self.__showUserChangeMessage(username, room, file_)
|
|
|
|
self.__showUserChangeMessage(username, room, file_)
|
|
|
|
self.userListChange()
|
|
|
|
self.userListChange()
|
|
|
|
|
|
|
|
|
|
|
|
def removeUser(self, username):
|
|
|
|
def removeUser(self, username):
|
|
|
|
if(self._users.has_key(username)):
|
|
|
|
if(self._users.has_key(username)):
|
|
|
|
self._users.pop(username)
|
|
|
|
self._users.pop(username)
|
|
|
|
message = getMessage("en", "left-notification").format(username)
|
|
|
|
message = getMessage("en", "left-notification").format(username)
|
|
|
|
self.ui.showMessage(message)
|
|
|
|
self.ui.showMessage(message)
|
|
|
|
self.userListChange()
|
|
|
|
self.userListChange()
|
|
|
|
|
|
|
|
|
|
|
|
def __displayModUserMessage(self, username, room, file_, user):
|
|
|
|
def __displayModUserMessage(self, username, room, file_, user):
|
|
|
|
if (file_ and not user.isFileSame(file_)):
|
|
|
|
if (file_ and not user.isFileSame(file_)):
|
|
|
|
self.__showUserChangeMessage(username, room, file_)
|
|
|
|
self.__showUserChangeMessage(username, room, file_)
|
|
|
|
@ -585,13 +591,13 @@ class SyncplayUserlist(object):
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
self.addUser(username, room, file_)
|
|
|
|
self.addUser(username, room, file_)
|
|
|
|
self.userListChange()
|
|
|
|
self.userListChange()
|
|
|
|
|
|
|
|
|
|
|
|
def areAllFilesInRoomSame(self):
|
|
|
|
def areAllFilesInRoomSame(self):
|
|
|
|
for user in self._users.itervalues():
|
|
|
|
for user in self._users.itervalues():
|
|
|
|
if(user.room == self.currentUser.room and user.file and not self.currentUser.isFileSame(user.file)):
|
|
|
|
if(user.room == self.currentUser.room and user.file and not self.currentUser.isFileSame(user.file)):
|
|
|
|
return False
|
|
|
|
return False
|
|
|
|
return True
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
def areYouAloneInRoom(self):
|
|
|
|
def areYouAloneInRoom(self):
|
|
|
|
for user in self._users.itervalues():
|
|
|
|
for user in self._users.itervalues():
|
|
|
|
if(user.room == self.currentUser.room):
|
|
|
|
if(user.room == self.currentUser.room):
|
|
|
|
@ -607,13 +613,13 @@ class SyncplayUserlist(object):
|
|
|
|
def userListChange(self):
|
|
|
|
def userListChange(self):
|
|
|
|
self._roomUsersChanged = True
|
|
|
|
self._roomUsersChanged = True
|
|
|
|
self.ui.userListChange()
|
|
|
|
self.ui.userListChange()
|
|
|
|
|
|
|
|
|
|
|
|
def roomStateConfirmed(self):
|
|
|
|
def roomStateConfirmed(self):
|
|
|
|
self._roomUsersChanged = False
|
|
|
|
self._roomUsersChanged = False
|
|
|
|
|
|
|
|
|
|
|
|
def hasRoomStateChanged(self):
|
|
|
|
def hasRoomStateChanged(self):
|
|
|
|
return self._roomUsersChanged
|
|
|
|
return self._roomUsersChanged
|
|
|
|
|
|
|
|
|
|
|
|
def showUserList(self):
|
|
|
|
def showUserList(self):
|
|
|
|
rooms = {}
|
|
|
|
rooms = {}
|
|
|
|
for user in self._users.itervalues():
|
|
|
|
for user in self._users.itervalues():
|
|
|
|
@ -623,41 +629,47 @@ class SyncplayUserlist(object):
|
|
|
|
if(self.currentUser.room not in rooms):
|
|
|
|
if(self.currentUser.room not in rooms):
|
|
|
|
rooms[self.currentUser.room] = []
|
|
|
|
rooms[self.currentUser.room] = []
|
|
|
|
rooms[self.currentUser.room].append(self.currentUser)
|
|
|
|
rooms[self.currentUser.room].append(self.currentUser)
|
|
|
|
|
|
|
|
rooms = self.sortList(rooms)
|
|
|
|
self.ui.showUserList(self.currentUser, rooms)
|
|
|
|
self.ui.showUserList(self.currentUser, rooms)
|
|
|
|
|
|
|
|
|
|
|
|
def clearList(self):
|
|
|
|
def clearList(self):
|
|
|
|
self._users = {}
|
|
|
|
self._users = {}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def sortList(self, rooms):
|
|
|
|
|
|
|
|
for room in rooms:
|
|
|
|
|
|
|
|
rooms[room] = sorted(rooms[room])
|
|
|
|
|
|
|
|
rooms = collections.OrderedDict(sorted(rooms.items(), key=lambda s: s[0].lower()))
|
|
|
|
|
|
|
|
return rooms
|
|
|
|
|
|
|
|
|
|
|
|
class UiManager(object):
|
|
|
|
class UiManager(object):
|
|
|
|
def __init__(self, client, ui):
|
|
|
|
def __init__(self, client, ui):
|
|
|
|
self._client = client
|
|
|
|
self._client = client
|
|
|
|
self.__ui = ui
|
|
|
|
self.__ui = ui
|
|
|
|
|
|
|
|
|
|
|
|
def showMessage(self, message, noPlayer = False, noTimestamp = False):
|
|
|
|
def showMessage(self, message, noPlayer=False, noTimestamp=False):
|
|
|
|
if(not noPlayer): self.showOSDMessage(message)
|
|
|
|
if(not noPlayer): self.showOSDMessage(message)
|
|
|
|
self.__ui.showMessage(message, noTimestamp)
|
|
|
|
self.__ui.showMessage(message, noTimestamp)
|
|
|
|
|
|
|
|
|
|
|
|
def showUserList(self, currentUser, rooms):
|
|
|
|
def showUserList(self, currentUser, rooms):
|
|
|
|
self.__ui.showUserList(currentUser, rooms)
|
|
|
|
self.__ui.showUserList(currentUser, rooms)
|
|
|
|
|
|
|
|
|
|
|
|
def showOSDMessage(self, message, duration = constants.OSD_DURATION):
|
|
|
|
def showOSDMessage(self, message, duration=constants.OSD_DURATION):
|
|
|
|
if(self._client._player):
|
|
|
|
if(self._client._player):
|
|
|
|
self._client._player.displayMessage(message, duration * 1000)
|
|
|
|
self._client._player.displayMessage(message, duration * 1000)
|
|
|
|
|
|
|
|
|
|
|
|
def showErrorMessage(self, message, criticalerror = False):
|
|
|
|
def showErrorMessage(self, message, criticalerror=False):
|
|
|
|
self.__ui.showErrorMessage(message, criticalerror)
|
|
|
|
self.__ui.showErrorMessage(message, criticalerror)
|
|
|
|
|
|
|
|
|
|
|
|
def promptFor(self, prompt):
|
|
|
|
def promptFor(self, prompt):
|
|
|
|
return self.__ui.promptFor(prompt)
|
|
|
|
return self.__ui.promptFor(prompt)
|
|
|
|
|
|
|
|
|
|
|
|
def userListChange(self):
|
|
|
|
def userListChange(self):
|
|
|
|
self.__ui.userListChange()
|
|
|
|
self.__ui.userListChange()
|
|
|
|
|
|
|
|
|
|
|
|
def markEndOfUserlist(self):
|
|
|
|
def markEndOfUserlist(self):
|
|
|
|
self.__ui.markEndOfUserlist()
|
|
|
|
self.__ui.markEndOfUserlist()
|
|
|
|
|
|
|
|
|
|
|
|
def drop(self):
|
|
|
|
def drop(self):
|
|
|
|
self.__ui.drop()
|
|
|
|
self.__ui.drop()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|