Merge branch 'master' of git://github.com/Uriziel/syncplay

This commit is contained in:
Joelixny 2014-03-26 18:40:33 -04:00
commit bbee87932a
8 changed files with 121 additions and 92 deletions

View File

@ -1,3 +1,3 @@
version = '1.2.7' version = '1.2.8'
milestone = 'Biscuit' milestone = 'Hammer'
projectURL = 'http://syncplay.pl/' projectURL = 'http://syncplay.pl/'

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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