Merge branch 'master' of git://github.com/Uriziel/syncplay
This commit is contained in:
commit
bbee87932a
@ -1,3 +1,3 @@
|
|||||||
version = '1.2.7'
|
version = '1.2.8'
|
||||||
milestone = 'Biscuit'
|
milestone = 'Hammer'
|
||||||
projectURL = 'http://syncplay.pl/'
|
projectURL = 'http://syncplay.pl/'
|
||||||
|
|||||||
@ -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,8 +19,9 @@ 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
|
||||||
@ -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)
|
||||||
@ -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'])
|
||||||
@ -302,7 +303,7 @@ class SyncplayClient(object):
|
|||||||
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)
|
||||||
@ -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
|
||||||
@ -434,7 +435,7 @@ class SyncplayClient(object):
|
|||||||
|
|
||||||
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
|
||||||
@ -443,7 +444,7 @@ class SyncplayClient(object):
|
|||||||
|
|
||||||
|
|
||||||
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_
|
||||||
@ -466,8 +467,13 @@ class SyncplayUser(object):
|
|||||||
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):
|
||||||
@ -509,7 +515,7 @@ 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
|
||||||
@ -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
|
||||||
@ -623,29 +629,35 @@ 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):
|
||||||
|
|||||||
@ -8,6 +8,8 @@ UI_TIME_FORMAT = "[%X] "
|
|||||||
CONFIG_NAMES = [".syncplay", "syncplay.ini"] #Syncplay searches first to last
|
CONFIG_NAMES = [".syncplay", "syncplay.ini"] #Syncplay searches first to last
|
||||||
DEFAULT_CONFIG_NAME_WINDOWS = "syncplay.ini"
|
DEFAULT_CONFIG_NAME_WINDOWS = "syncplay.ini"
|
||||||
DEFAULT_CONFIG_NAME_LINUX = ".syncplay"
|
DEFAULT_CONFIG_NAME_LINUX = ".syncplay"
|
||||||
|
RECENT_CLIENT_THRESHOLD = "1.2.7" #This and higher considered 'recent' clients (no warnings)
|
||||||
|
WARN_OLD_CLIENTS = True #Use MOTD to inform old clients to upgrade
|
||||||
|
|
||||||
#Changing these might be ok
|
#Changing these might be ok
|
||||||
REWIND_THRESHOLD = 4
|
REWIND_THRESHOLD = 4
|
||||||
|
|||||||
@ -163,6 +163,9 @@ en = {
|
|||||||
|
|
||||||
"help-tooltip" : "Opens the Syncplay.pl user guide.",
|
"help-tooltip" : "Opens the Syncplay.pl user guide.",
|
||||||
|
|
||||||
|
# Server messages to client
|
||||||
|
"new-syncplay-available-motd-message" : "<NOTICE> You are using Syncplay {} but a newer version is available from http://syncplay.pl </NOTICE>", #ClientVersion
|
||||||
|
|
||||||
# Server notifications
|
# Server notifications
|
||||||
"welcome-server-notification" : "Welcome to Syncplay server, ver. {0}", #version
|
"welcome-server-notification" : "Welcome to Syncplay server, ver. {0}", #version
|
||||||
"client-connected-room-server-notification" : "{0}({2}) connected to room '{1}'", #username, host, room
|
"client-connected-room-server-notification" : "{0}({2}) connected to room '{1}'", #username, host, room
|
||||||
|
|||||||
@ -291,9 +291,9 @@ class SyncServerProtocol(JSONCommandProtocol):
|
|||||||
return
|
return
|
||||||
self._factory.addWatcher(self, username, roomName, roomPassword)
|
self._factory.addWatcher(self, username, roomName, roomPassword)
|
||||||
self._logged = True
|
self._logged = True
|
||||||
self.sendHello()
|
self.sendHello(version)
|
||||||
|
|
||||||
def sendHello(self):
|
def sendHello(self, clientVersion):
|
||||||
hello = {}
|
hello = {}
|
||||||
username = self._factory.watcherGetUsername(self)
|
username = self._factory.watcherGetUsername(self)
|
||||||
hello["username"] = username
|
hello["username"] = username
|
||||||
@ -301,7 +301,7 @@ class SyncServerProtocol(JSONCommandProtocol):
|
|||||||
room = self._factory.watcherGetRoom(self)
|
room = self._factory.watcherGetRoom(self)
|
||||||
if(room): hello["room"] = {"name": room}
|
if(room): hello["room"] = {"name": room}
|
||||||
hello["version"] = syncplay.version
|
hello["version"] = syncplay.version
|
||||||
hello["motd"] = self._factory.getMotd(userIp, username, room)
|
hello["motd"] = self._factory.getMotd(userIp, username, room, clientVersion)
|
||||||
self.sendMessage({"Hello": hello})
|
self.sendMessage({"Hello": hello})
|
||||||
|
|
||||||
@requireLogged
|
@requireLogged
|
||||||
|
|||||||
@ -136,15 +136,24 @@ class SyncFactory(Factory):
|
|||||||
position += timePassedSinceSet
|
position += timePassedSinceSet
|
||||||
return paused, position
|
return paused, position
|
||||||
|
|
||||||
def getMotd(self, userIp, username, room):
|
def getMotd(self, userIp, username, room, clientVersion):
|
||||||
|
oldClient = False
|
||||||
|
if constants.WARN_OLD_CLIENTS:
|
||||||
|
if int(clientVersion.replace(".","")) < int(constants.RECENT_CLIENT_THRESHOLD.replace(".","")):
|
||||||
|
oldClient = True
|
||||||
if(self._motdFilePath and os.path.isfile(self._motdFilePath)):
|
if(self._motdFilePath and os.path.isfile(self._motdFilePath)):
|
||||||
tmpl = codecs.open(self._motdFilePath, "r", "utf-8-sig").read()
|
tmpl = codecs.open(self._motdFilePath, "r", "utf-8-sig").read()
|
||||||
args = dict(version=syncplay.version, userIp=userIp, username=username, room=room)
|
args = dict(version=syncplay.version, userIp=userIp, username=username, room=room)
|
||||||
try:
|
try:
|
||||||
motd = Template(tmpl).substitute(args)
|
motd = Template(tmpl).substitute(args)
|
||||||
|
if oldClient:
|
||||||
|
motdwarning = getMessage("en","new-syncplay-available-motd-message").format(clientVersion)
|
||||||
|
motd = "{}\n{}".format(motdwarning, motd)
|
||||||
return motd if len(motd) < constants.SERVER_MAX_TEMPLATE_LENGTH else getMessage("en", "server-messed-up-motd-too-long").format(constants.SERVER_MAX_TEMPLATE_LENGTH, len(motd))
|
return motd if len(motd) < constants.SERVER_MAX_TEMPLATE_LENGTH else getMessage("en", "server-messed-up-motd-too-long").format(constants.SERVER_MAX_TEMPLATE_LENGTH, len(motd))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return getMessage("en", "server-messed-up-motd-unescaped-placeholders")
|
return getMessage("en", "server-messed-up-motd-unescaped-placeholders")
|
||||||
|
elif oldClient:
|
||||||
|
return getMessage("en", "new-syncplay-available-motd-message").format(clientVersion)
|
||||||
else:
|
else:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,7 @@
|
|||||||
from syncplay.ui.gui import MainWindow as GraphicalUI
|
try:
|
||||||
|
from syncplay.ui.gui import MainWindow as GraphicalUI
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
from syncplay.ui.consoleUI import ConsoleUI
|
from syncplay.ui.consoleUI import ConsoleUI
|
||||||
|
|
||||||
def getUi(graphical=True):
|
def getUi(graphical=True):
|
||||||
|
|||||||
@ -211,7 +211,7 @@ class MainWindow(QtGui.QMainWindow):
|
|||||||
t = self._syncplayClient.getUserOffset() + sign * t
|
t = self._syncplayClient.getUserOffset() + sign * t
|
||||||
self._syncplayClient.setUserOffset(t)
|
self._syncplayClient.setUserOffset(t)
|
||||||
else:
|
else:
|
||||||
self.showMessage("Invalid offset value", True)
|
self.showErrorMessage("Invalid offset value")
|
||||||
|
|
||||||
def openUserGuide(self):
|
def openUserGuide(self):
|
||||||
if sys.platform.startswith('linux'):
|
if sys.platform.startswith('linux'):
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user