Merge branch 'master' into 1.4.x
This commit is contained in:
commit
d7fb9cb0ec
@ -661,6 +661,7 @@ guiIcons = ['resources/accept.png', 'resources/arrow_undo.png', 'resources/clock
|
|||||||
'resources/film_edit.png',
|
'resources/film_edit.png',
|
||||||
'resources/shield_edit.png',
|
'resources/shield_edit.png',
|
||||||
'resources/shield_add.png',
|
'resources/shield_add.png',
|
||||||
|
'resources/email_go.png',
|
||||||
'resources/world_add.png', 'resources/film_add.png', 'resources/delete.png', 'resources/spinner.mng'
|
'resources/world_add.png', 'resources/film_add.png', 'resources/delete.png', 'resources/spinner.mng'
|
||||||
]
|
]
|
||||||
resources = ["resources/icon.ico", "resources/syncplay.png"]
|
resources = ["resources/icon.ico", "resources/syncplay.png"]
|
||||||
@ -684,7 +685,7 @@ info = dict(
|
|||||||
options={'py2exe': {
|
options={'py2exe': {
|
||||||
'dist_dir': OUT_DIR,
|
'dist_dir': OUT_DIR,
|
||||||
'packages': 'PySide.QtUiTools',
|
'packages': 'PySide.QtUiTools',
|
||||||
'includes': 'twisted, sys, encodings, datetime, os, time, math, PySide, liburl, ast',
|
'includes': 'twisted, sys, encodings, datetime, os, time, math, PySide, liburl, ast, unicodedata',
|
||||||
'excludes': 'venv, _ssl, doctest, pdb, unittest, win32clipboard, win32file, win32pdh, win32security, win32trace, win32ui, winxpgui, win32pipe, win32process, Tkinter',
|
'excludes': 'venv, _ssl, doctest, pdb, unittest, win32clipboard, win32file, win32pdh, win32security, win32trace, win32ui, winxpgui, win32pipe, win32process, Tkinter',
|
||||||
'dll_excludes': 'msvcr71.dll, MSVCP90.dll, POWRPROF.dll',
|
'dll_excludes': 'msvcr71.dll, MSVCP90.dll, POWRPROF.dll',
|
||||||
'optimize': 2,
|
'optimize': 2,
|
||||||
|
|||||||
BIN
resources/email_go.png
Normal file
BIN
resources/email_go.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 754 B |
@ -1,4 +1,4 @@
|
|||||||
version = '1.4.0'
|
version = '1.5.0'
|
||||||
milestone = 'Yoitsu'
|
milestone = 'Yoitsu'
|
||||||
release_number = '38'
|
release_number = '39'
|
||||||
projectURL = 'http://syncplay.pl/'
|
projectURL = 'http://syncplay.pl/'
|
||||||
|
|||||||
@ -39,7 +39,7 @@ class SyncClientFactory(ClientFactory):
|
|||||||
self._timesTried += 1
|
self._timesTried += 1
|
||||||
self._client.ui.showMessage(getMessage("reconnection-attempt-notification"))
|
self._client.ui.showMessage(getMessage("reconnection-attempt-notification"))
|
||||||
self.reconnecting = True
|
self.reconnecting = True
|
||||||
reactor.callLater(0.1 * (2 ** self._timesTried), connector.connect)
|
reactor.callLater(0.1 * (2 ** min(self._timesTried,5)), connector.connect)
|
||||||
else:
|
else:
|
||||||
message = getMessage("disconnection-notification")
|
message = getMessage("disconnection-notification")
|
||||||
self._client.ui.showErrorMessage(message)
|
self._client.ui.showErrorMessage(message)
|
||||||
@ -71,6 +71,8 @@ class SyncplayClient(object):
|
|||||||
self.lastControlPasswordAttempt = None
|
self.lastControlPasswordAttempt = None
|
||||||
self.serverVersion = "0.0.0"
|
self.serverVersion = "0.0.0"
|
||||||
|
|
||||||
|
self.serverFeatures = {}
|
||||||
|
|
||||||
self.lastRewindTime = None
|
self.lastRewindTime = None
|
||||||
self.lastLeftTime = 0
|
self.lastLeftTime = 0
|
||||||
self.lastPausedOnLeaveTime = None
|
self.lastPausedOnLeaveTime = None
|
||||||
@ -201,7 +203,7 @@ class SyncplayClient(object):
|
|||||||
if pauseChange and paused and currentLength > constants.PLAYLIST_LOAD_NEXT_FILE_MINIMUM_LENGTH\
|
if pauseChange and paused and currentLength > constants.PLAYLIST_LOAD_NEXT_FILE_MINIMUM_LENGTH\
|
||||||
and abs(position - currentLength ) < constants.PLAYLIST_LOAD_NEXT_FILE_TIME_FROM_END_THRESHOLD:
|
and abs(position - currentLength ) < constants.PLAYLIST_LOAD_NEXT_FILE_TIME_FROM_END_THRESHOLD:
|
||||||
self.playlist.advancePlaylistCheck()
|
self.playlist.advancePlaylistCheck()
|
||||||
elif pauseChange and utils.meetsMinVersion(self.serverVersion, constants.USER_READY_MIN_VERSION):
|
elif pauseChange and self.serverFeatures["readiness"]:
|
||||||
if currentLength == 0 or currentLength == -1 or\
|
if currentLength == 0 or currentLength == -1 or\
|
||||||
not (not self.playlist.notJustChangedPlaylist() and abs(position - currentLength ) < constants.PLAYLIST_LOAD_NEXT_FILE_TIME_FROM_END_THRESHOLD):
|
not (not self.playlist.notJustChangedPlaylist() and abs(position - currentLength ) < constants.PLAYLIST_LOAD_NEXT_FILE_TIME_FROM_END_THRESHOLD):
|
||||||
pauseChange = self._toggleReady(pauseChange, paused)
|
pauseChange = self._toggleReady(pauseChange, paused)
|
||||||
@ -532,13 +534,25 @@ class SyncplayClient(object):
|
|||||||
size = 0
|
size = 0
|
||||||
return filename, size
|
return filename, size
|
||||||
|
|
||||||
def setServerVersion(self, version):
|
def setServerVersion(self, version, featureList):
|
||||||
self.serverVersion = version
|
self.serverVersion = version
|
||||||
self.checkForFeatureSupport()
|
self.checkForFeatureSupport(featureList)
|
||||||
|
|
||||||
def checkForFeatureSupport(self):
|
def checkForFeatureSupport(self, featureList):
|
||||||
|
self.serverFeatures = {
|
||||||
|
"featureList": utils.meetsMinVersion(self.serverVersion, constants.FEATURE_LIST_MIN_VERSION),
|
||||||
|
"sharedPlaylists": utils.meetsMinVersion(self.serverVersion, constants.SHARED_PLAYLIST_MIN_VERSION),
|
||||||
|
"chat": utils.meetsMinVersion(self.serverVersion, constants.CHAT_MIN_VERSION),
|
||||||
|
"readiness": utils.meetsMinVersion(self.serverVersion, constants.USER_READY_MIN_VERSION),
|
||||||
|
"managedRooms": utils.meetsMinVersion(self.serverVersion, constants.CONTROLLED_ROOMS_MIN_VERSION)
|
||||||
|
}
|
||||||
|
if featureList:
|
||||||
|
self.serverFeatures.update(featureList)
|
||||||
if not utils.meetsMinVersion(self.serverVersion, constants.SHARED_PLAYLIST_MIN_VERSION):
|
if not utils.meetsMinVersion(self.serverVersion, constants.SHARED_PLAYLIST_MIN_VERSION):
|
||||||
self.ui.showErrorMessage(getMessage("shared-playlists-not-supported-by-server-error").format(constants.SHARED_PLAYLIST_MIN_VERSION, self.serverVersion))
|
self.ui.showErrorMessage(getMessage("shared-playlists-not-supported-by-server-error").format(constants.SHARED_PLAYLIST_MIN_VERSION, self.serverVersion))
|
||||||
|
elif not self.serverFeatures["sharedPlaylists"]:
|
||||||
|
self.ui.showErrorMessage(getMessage("shared-playlists-disabled-by-server-error"))
|
||||||
|
self.ui.setFeatures(self.serverFeatures)
|
||||||
|
|
||||||
def getSanitizedCurrentUserFile(self):
|
def getSanitizedCurrentUserFile(self):
|
||||||
if self.userlist.currentUser.file:
|
if self.userlist.currentUser.file:
|
||||||
@ -572,6 +586,11 @@ class SyncplayClient(object):
|
|||||||
if resetAutoplay:
|
if resetAutoplay:
|
||||||
self.resetAutoPlayState()
|
self.resetAutoPlayState()
|
||||||
|
|
||||||
|
def sendChat(self,message):
|
||||||
|
if self._protocol and self._protocol.logged:
|
||||||
|
message = utils.truncateText(message,constants.MAX_CHAT_MESSAGE_LENGTH)
|
||||||
|
self._protocol.sendChatMessage(message)
|
||||||
|
|
||||||
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:
|
||||||
@ -590,7 +609,11 @@ class SyncplayClient(object):
|
|||||||
return self._protocol and self._protocol.logged and self.userlist.currentUser.room
|
return self._protocol and self._protocol.logged and self.userlist.currentUser.room
|
||||||
|
|
||||||
def sharedPlaylistIsEnabled(self):
|
def sharedPlaylistIsEnabled(self):
|
||||||
return self._config['sharedPlaylistEnabled']
|
if self.serverFeatures.has_key("sharedPlaylists") and not self.serverFeatures["sharedPlaylists"]:
|
||||||
|
sharedPlaylistEnabled = False
|
||||||
|
else:
|
||||||
|
sharedPlaylistEnabled = self._config['sharedPlaylistEnabled']
|
||||||
|
return sharedPlaylistEnabled
|
||||||
|
|
||||||
def connected(self):
|
def connected(self):
|
||||||
readyState = self._config['readyAtStart'] if self.userlist.currentUser.isReady() is None else self.userlist.currentUser.isReady()
|
readyState = self._config['readyAtStart'] if self.userlist.currentUser.isReady() is None else self.userlist.currentUser.isReady()
|
||||||
@ -1025,13 +1048,12 @@ class SyncplayUserlist(object):
|
|||||||
self._roomUsersChanged = True
|
self._roomUsersChanged = True
|
||||||
|
|
||||||
def isReadinessSupported(self):
|
def isReadinessSupported(self):
|
||||||
# TODO: Return False if server is run with --disable-ready
|
|
||||||
if not utils.meetsMinVersion(self._client.serverVersion,constants.USER_READY_MIN_VERSION):
|
if not utils.meetsMinVersion(self._client.serverVersion,constants.USER_READY_MIN_VERSION):
|
||||||
return False
|
return False
|
||||||
elif self.onlyUserInRoomWhoSupportsReadiness():
|
elif self.onlyUserInRoomWhoSupportsReadiness():
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
return True
|
return self._client.serverFeatures["readiness"]
|
||||||
|
|
||||||
def isRoomSame(self, room):
|
def isRoomSame(self, room):
|
||||||
if room and self.currentUser.room and self.currentUser.room == room:
|
if room and self.currentUser.room and self.currentUser.room == room:
|
||||||
@ -1314,6 +1336,9 @@ class UiManager(object):
|
|||||||
def fileSwitchFoundFiles(self):
|
def fileSwitchFoundFiles(self):
|
||||||
self.__ui.fileSwitchFoundFiles()
|
self.__ui.fileSwitchFoundFiles()
|
||||||
|
|
||||||
|
def setFeatures(self, featureList):
|
||||||
|
self.__ui.setFeatures(featureList)
|
||||||
|
|
||||||
def showDebugMessage(self, message):
|
def showDebugMessage(self, message):
|
||||||
if constants.DEBUG_MODE and message.rstrip():
|
if constants.DEBUG_MODE and message.rstrip():
|
||||||
sys.stderr.write("{}{}\n".format(time.strftime(constants.UI_TIME_FORMAT, time.localtime()),message.rstrip()))
|
sys.stderr.write("{}{}\n".format(time.strftime(constants.UI_TIME_FORMAT, time.localtime()),message.rstrip()))
|
||||||
|
|||||||
@ -46,7 +46,7 @@ MINIMUM_SLOWDOWN_THRESHOLD = 1.3
|
|||||||
SLOWDOWN_RESET_THRESHOLD = 0.1
|
SLOWDOWN_RESET_THRESHOLD = 0.1
|
||||||
DIFFERENT_DURATION_THRESHOLD = 2.5
|
DIFFERENT_DURATION_THRESHOLD = 2.5
|
||||||
PROTOCOL_TIMEOUT = 12.5
|
PROTOCOL_TIMEOUT = 12.5
|
||||||
RECONNECT_RETRIES = 10
|
RECONNECT_RETRIES = 999
|
||||||
SERVER_STATE_INTERVAL = 1
|
SERVER_STATE_INTERVAL = 1
|
||||||
WARNING_OSD_MESSAGES_LOOP_INTERVAL = 1
|
WARNING_OSD_MESSAGES_LOOP_INTERVAL = 1
|
||||||
AUTOPLAY_DELAY = 3.0
|
AUTOPLAY_DELAY = 3.0
|
||||||
@ -55,6 +55,12 @@ SYNC_ON_PAUSE = True # Client seek to global position - subtitles may disappear
|
|||||||
PLAYLIST_MAX_CHARACTERS = 10000
|
PLAYLIST_MAX_CHARACTERS = 10000
|
||||||
PLAYLIST_MAX_ITEMS = 250
|
PLAYLIST_MAX_ITEMS = 250
|
||||||
|
|
||||||
|
# Maximum character lengths (for client and server)
|
||||||
|
MAX_CHAT_MESSAGE_LENGTH = 50 # Number of displayed characters
|
||||||
|
MAX_USERNAME_LENGTH = 12 # Number of displayed characters
|
||||||
|
MAX_ROOM_NAME_LENGTH = 35 # Number of displayed characters
|
||||||
|
MAX_FILENAME_LENGTH = 250 # Number of displayed characters
|
||||||
|
|
||||||
# Options for the File Switch feature:
|
# Options for the File Switch feature:
|
||||||
FOLDER_SEARCH_FIRST_FILE_TIMEOUT = 15.0 # Secs - How long to wait to find the first file in folder search (to take account of HDD spin up)
|
FOLDER_SEARCH_FIRST_FILE_TIMEOUT = 15.0 # Secs - How long to wait to find the first file in folder search (to take account of HDD spin up)
|
||||||
FOLDER_SEARCH_TIMEOUT = 6.0 # Secs - How long to wait until searches in folder to update cache are aborted (after first file is found)
|
FOLDER_SEARCH_TIMEOUT = 6.0 # Secs - How long to wait until searches in folder to update cache are aborted (after first file is found)
|
||||||
@ -66,6 +72,7 @@ FILENAME_STRIP_REGEX = u"[-~_\.\[\](): ]"
|
|||||||
CONTROL_PASSWORD_STRIP_REGEX = u"[^a-zA-Z0-9\-]"
|
CONTROL_PASSWORD_STRIP_REGEX = u"[^a-zA-Z0-9\-]"
|
||||||
ROOM_NAME_STRIP_REGEX = u"^(\+)(?P<roomnamebase>.*)(:)(\w{12})$"
|
ROOM_NAME_STRIP_REGEX = u"^(\+)(?P<roomnamebase>.*)(:)(\w{12})$"
|
||||||
COMMANDS_UNDO = ["u", "undo", "revert"]
|
COMMANDS_UNDO = ["u", "undo", "revert"]
|
||||||
|
COMMANDS_CHAT = ["ch","chat"]
|
||||||
COMMANDS_LIST = ["l", "list", "users"]
|
COMMANDS_LIST = ["l", "list", "users"]
|
||||||
COMMANDS_PAUSE = ["p", "play", "pause"]
|
COMMANDS_PAUSE = ["p", "play", "pause"]
|
||||||
COMMANDS_ROOM = ["r", "room"]
|
COMMANDS_ROOM = ["r", "room"]
|
||||||
@ -81,6 +88,8 @@ MPV_UNRESPONSIVE_THRESHOLD = 60.0
|
|||||||
CONTROLLED_ROOMS_MIN_VERSION = "1.3.0"
|
CONTROLLED_ROOMS_MIN_VERSION = "1.3.0"
|
||||||
USER_READY_MIN_VERSION = "1.3.0"
|
USER_READY_MIN_VERSION = "1.3.0"
|
||||||
SHARED_PLAYLIST_MIN_VERSION = "1.4.0"
|
SHARED_PLAYLIST_MIN_VERSION = "1.4.0"
|
||||||
|
CHAT_MIN_VERSION = "1.5.0"
|
||||||
|
FEATURE_LIST_MIN_VERSION = "1.5.0"
|
||||||
MPC_PATHS = [
|
MPC_PATHS = [
|
||||||
r"c:\program files (x86)\mpc-hc\mpc-hc.exe",
|
r"c:\program files (x86)\mpc-hc\mpc-hc.exe",
|
||||||
r"c:\program files\mpc-hc\mpc-hc.exe",
|
r"c:\program files\mpc-hc\mpc-hc.exe",
|
||||||
@ -143,7 +152,8 @@ STYLE_READY_PUSHBUTTON = "QPushButton { text-align: left; padding: 10px 5px 10px
|
|||||||
STYLE_AUTO_PLAY_PUSHBUTTON = "QPushButton { text-align: left; padding: 5px 5px 5px 5px; }"
|
STYLE_AUTO_PLAY_PUSHBUTTON = "QPushButton { text-align: left; padding: 5px 5px 5px 5px; }"
|
||||||
STYLE_NOTIFICATIONBOX = "Username { color: #367AA9; font-weight:bold; }"
|
STYLE_NOTIFICATIONBOX = "Username { color: #367AA9; font-weight:bold; }"
|
||||||
STYLE_CONTACT_INFO = u"<span style=\"color: grey\"><strong><small>{}</span><br /><br />" # Contact info message
|
STYLE_CONTACT_INFO = u"<span style=\"color: grey\"><strong><small>{}</span><br /><br />" # Contact info message
|
||||||
STYLE_USERNAME = "color: #367AA9; font-weight:bold;"
|
STYLE_USER_MESSAGE = u"<span style=\"{}\"><{}></span> {}"
|
||||||
|
STYLE_USERNAME = u"color: #367AA9; font-weight:bold;"
|
||||||
STYLE_ERRORNOTIFICATION = "color: red;"
|
STYLE_ERRORNOTIFICATION = "color: red;"
|
||||||
STYLE_DIFFERENTITEM_COLOR = 'red'
|
STYLE_DIFFERENTITEM_COLOR = 'red'
|
||||||
STYLE_NOFILEITEM_COLOR = 'blue'
|
STYLE_NOFILEITEM_COLOR = 'blue'
|
||||||
@ -170,6 +180,7 @@ UI_COMMAND_REGEX = r"^(?P<command>[^\ ]+)(?:\ (?P<parameter>.+))?"
|
|||||||
UI_OFFSET_REGEX = r"^(?:o|offset)\ ?(?P<sign>[/+-])?(?P<time>\d{1,9}(?:[^\d\.](?:\d{1,9})){0,2}(?:\.(?:\d{1,3}))?)$"
|
UI_OFFSET_REGEX = r"^(?:o|offset)\ ?(?P<sign>[/+-])?(?P<time>\d{1,9}(?:[^\d\.](?:\d{1,9})){0,2}(?:\.(?:\d{1,3}))?)$"
|
||||||
UI_SEEK_REGEX = r"^(?:s|seek)?\ ?(?P<sign>[+-])?(?P<time>\d{1,4}(?:[^\d\.](?:\d{1,6})){0,2}(?:\.(?:\d{1,3}))?)$"
|
UI_SEEK_REGEX = r"^(?:s|seek)?\ ?(?P<sign>[+-])?(?P<time>\d{1,4}(?:[^\d\.](?:\d{1,6})){0,2}(?:\.(?:\d{1,3}))?)$"
|
||||||
PARSE_TIME_REGEX = r'(:?(?:(?P<hours>\d+?)[^\d\.])?(?:(?P<minutes>\d+?))?[^\d\.])?(?P<seconds>\d+?)(?:\.(?P<miliseconds>\d+?))?$'
|
PARSE_TIME_REGEX = r'(:?(?:(?P<hours>\d+?)[^\d\.])?(?:(?P<minutes>\d+?))?[^\d\.])?(?P<seconds>\d+?)(?:\.(?P<miliseconds>\d+?))?$'
|
||||||
|
MESSAGE_WITH_USERNAME_REGEX = "^(<(?P<username>[^<>]+)>)(?P<message>.*)"
|
||||||
SERVER_MAX_TEMPLATE_LENGTH = 10000
|
SERVER_MAX_TEMPLATE_LENGTH = 10000
|
||||||
PRIVACY_SENDRAW_MODE = "SendRaw"
|
PRIVACY_SENDRAW_MODE = "SendRaw"
|
||||||
PRIVACY_SENDHASHED_MODE = "SendHashed"
|
PRIVACY_SENDHASHED_MODE = "SendHashed"
|
||||||
|
|||||||
@ -85,6 +85,7 @@ de = {
|
|||||||
"commandlist-notification/toggle" : u"\tt - Bereitschaftsanzeige umschalten",
|
"commandlist-notification/toggle" : u"\tt - Bereitschaftsanzeige umschalten",
|
||||||
"commandlist-notification/create" : u"\tc [name] - erstelle zentral gesteuerten Raum mit dem aktuellen Raumnamen",
|
"commandlist-notification/create" : u"\tc [name] - erstelle zentral gesteuerten Raum mit dem aktuellen Raumnamen",
|
||||||
"commandlist-notification/auth" : u"\ta [password] - authentifiziere als Raumleiter mit Passwort",
|
"commandlist-notification/auth" : u"\ta [password] - authentifiziere als Raumleiter mit Passwort",
|
||||||
|
"commandlist-notification/chat" : "\tch [message] - send a chat message in a room", # TODO: Translate
|
||||||
"syncplay-version-notification" : u"Syncplay Version: {}", # syncplay.version
|
"syncplay-version-notification" : u"Syncplay Version: {}", # syncplay.version
|
||||||
"more-info-notification" : u"Weitere Informationen auf: {}", # projectURL
|
"more-info-notification" : u"Weitere Informationen auf: {}", # projectURL
|
||||||
|
|
||||||
@ -135,6 +136,7 @@ de = {
|
|||||||
|
|
||||||
"not-supported-by-server-error" : u"Dieses Feature wird vom Server nicht unterstützt. Es wird ein Server mit Syncplay Version {}+ benötigt, aktuell verwendet wird jedoch Version {}.", #minVersion, serverVersion
|
"not-supported-by-server-error" : u"Dieses Feature wird vom Server nicht unterstützt. Es wird ein Server mit Syncplay Version {}+ benötigt, aktuell verwendet wird jedoch Version {}.", #minVersion, serverVersion
|
||||||
"shared-playlists-not-supported-by-server-error" : "The shared playlists feature may not be supported by the server. To ensure that it works correctly requires a server running Syncplay {}+, but the server is running Syncplay {}.", #minVersion, serverVersion # TODO: Translate
|
"shared-playlists-not-supported-by-server-error" : "The shared playlists feature may not be supported by the server. To ensure that it works correctly requires a server running Syncplay {}+, but the server is running Syncplay {}.", #minVersion, serverVersion # TODO: Translate
|
||||||
|
"shared-playlists-disabled-by-server-error" : "The shared playlist feature has been disabled in the server configuration. To use this feature you will need to connect to a different server.", # TODO: Translate
|
||||||
|
|
||||||
"invalid-seek-value" : u"Ungültige Zeitangabe",
|
"invalid-seek-value" : u"Ungültige Zeitangabe",
|
||||||
"invalid-offset-value" : u"Ungültiger Offset-Wert",
|
"invalid-offset-value" : u"Ungültiger Offset-Wert",
|
||||||
@ -249,6 +251,8 @@ de = {
|
|||||||
"autoplay-guipushbuttonlabel" : u"Automatisch abspielen wenn alle bereit sind",
|
"autoplay-guipushbuttonlabel" : u"Automatisch abspielen wenn alle bereit sind",
|
||||||
"autoplay-minimum-label" : u"Minimum an Nutzern:",
|
"autoplay-minimum-label" : u"Minimum an Nutzern:",
|
||||||
|
|
||||||
|
"sendmessage-label" : u"Send", # TODO: Translate
|
||||||
|
|
||||||
"ready-guipushbuttonlabel" : u"Ich bin bereit den Film anzuschauen!",
|
"ready-guipushbuttonlabel" : u"Ich bin bereit den Film anzuschauen!",
|
||||||
|
|
||||||
"roomuser-heading-label" : u"Raum / Benutzer",
|
"roomuser-heading-label" : u"Raum / Benutzer",
|
||||||
@ -353,6 +357,7 @@ de = {
|
|||||||
"ready-tooltip" : u"Zeigt an, ob du bereit zum anschauen bist",
|
"ready-tooltip" : u"Zeigt an, ob du bereit zum anschauen bist",
|
||||||
"autoplay-tooltip" : u"Automatisch abspielen, wenn alle Nutzer bereit sind oder die minimale Nutzerzahl erreicht ist.",
|
"autoplay-tooltip" : u"Automatisch abspielen, wenn alle Nutzer bereit sind oder die minimale Nutzerzahl erreicht ist.",
|
||||||
"switch-to-file-tooltip" : u"Doppelklicken um zu {} zu wechseln", # Filename
|
"switch-to-file-tooltip" : u"Doppelklicken um zu {} zu wechseln", # Filename
|
||||||
|
"sendmessage-tooltip" : u"Send message to room", # TODO: Translate
|
||||||
|
|
||||||
# In-userlist notes (GUI)
|
# In-userlist notes (GUI)
|
||||||
"differentsize-note" : u"Verschiedene Größe!",
|
"differentsize-note" : u"Verschiedene Größe!",
|
||||||
@ -378,6 +383,7 @@ de = {
|
|||||||
"server-salt-argument" : u"zufällige Zeichenkette, die zur Erstellung von Passwörtern verwendet wird",
|
"server-salt-argument" : u"zufällige Zeichenkette, die zur Erstellung von Passwörtern verwendet wird",
|
||||||
"server-disable-ready-argument" : u"Bereitschaftsfeature deaktivieren",
|
"server-disable-ready-argument" : u"Bereitschaftsfeature deaktivieren",
|
||||||
"server-motd-argument": u"Pfad zur Datei, von der die Nachricht des Tages geladen wird",
|
"server-motd-argument": u"Pfad zur Datei, von der die Nachricht des Tages geladen wird",
|
||||||
|
"server-chat-argument" : "Should chat be disabled?", # TODO: Translate
|
||||||
"server-messed-up-motd-unescaped-placeholders": u"Die Nachricht des Tages hat unmaskierte Platzhalter. Alle $-Zeichen sollten verdoppelt werden ($$).",
|
"server-messed-up-motd-unescaped-placeholders": u"Die Nachricht des Tages hat unmaskierte Platzhalter. Alle $-Zeichen sollten verdoppelt werden ($$).",
|
||||||
"server-messed-up-motd-too-long": u"Die Nachricht des Tages ist zu lang - Maximal {} Zeichen, aktuell {}.",
|
"server-messed-up-motd-too-long": u"Die Nachricht des Tages ist zu lang - Maximal {} Zeichen, aktuell {}.",
|
||||||
|
|
||||||
|
|||||||
@ -85,6 +85,7 @@ en = {
|
|||||||
"commandlist-notification/toggle" : u"\tt - toggles whether you are ready to watch or not",
|
"commandlist-notification/toggle" : u"\tt - toggles whether you are ready to watch or not",
|
||||||
"commandlist-notification/create" : "\tc [name] - create managed room using name of current room",
|
"commandlist-notification/create" : "\tc [name] - create managed room using name of current room",
|
||||||
"commandlist-notification/auth" : "\ta [password] - authenticate as room operator with operator password",
|
"commandlist-notification/auth" : "\ta [password] - authenticate as room operator with operator password",
|
||||||
|
"commandlist-notification/chat" : "\tch [message] - send a chat message in a room",
|
||||||
"syncplay-version-notification" : "Syncplay version: {}", # syncplay.version
|
"syncplay-version-notification" : "Syncplay version: {}", # syncplay.version
|
||||||
"more-info-notification" : "More info available at: {}", # projectURL
|
"more-info-notification" : "More info available at: {}", # projectURL
|
||||||
|
|
||||||
@ -133,6 +134,7 @@ en = {
|
|||||||
|
|
||||||
"not-supported-by-server-error" : "This feature is not supported by the server. The feature requires a server running Syncplay {}+, but the server is running Syncplay {}.", #minVersion, serverVersion
|
"not-supported-by-server-error" : "This feature is not supported by the server. The feature requires a server running Syncplay {}+, but the server is running Syncplay {}.", #minVersion, serverVersion
|
||||||
"shared-playlists-not-supported-by-server-error" : "The shared playlists feature may not be supported by the server. To ensure that it works correctly requires a server running Syncplay {}+, but the server is running Syncplay {}.", #minVersion, serverVersion
|
"shared-playlists-not-supported-by-server-error" : "The shared playlists feature may not be supported by the server. To ensure that it works correctly requires a server running Syncplay {}+, but the server is running Syncplay {}.", #minVersion, serverVersion
|
||||||
|
"shared-playlists-disabled-by-server-error" : "The shared playlist feature has been disabled in the server configuration. To use this feature you will need to connect to a different server.",
|
||||||
|
|
||||||
"invalid-seek-value" : u"Invalid seek value",
|
"invalid-seek-value" : u"Invalid seek value",
|
||||||
"invalid-offset-value" : u"Invalid offset value",
|
"invalid-offset-value" : u"Invalid offset value",
|
||||||
@ -249,6 +251,8 @@ en = {
|
|||||||
"autoplay-guipushbuttonlabel" : u"Play when all ready",
|
"autoplay-guipushbuttonlabel" : u"Play when all ready",
|
||||||
"autoplay-minimum-label" : u"Min users:",
|
"autoplay-minimum-label" : u"Min users:",
|
||||||
|
|
||||||
|
"sendmessage-label" : u"Send",
|
||||||
|
|
||||||
"ready-guipushbuttonlabel" : u"I'm ready to watch!",
|
"ready-guipushbuttonlabel" : u"I'm ready to watch!",
|
||||||
|
|
||||||
"roomuser-heading-label" : "Room / User",
|
"roomuser-heading-label" : "Room / User",
|
||||||
@ -351,6 +355,7 @@ en = {
|
|||||||
"ready-tooltip" : "Indicates whether you are ready to watch.",
|
"ready-tooltip" : "Indicates whether you are ready to watch.",
|
||||||
"autoplay-tooltip" : "Auto-play when all users who have readiness indicator are ready and minimum user threshold met.",
|
"autoplay-tooltip" : "Auto-play when all users who have readiness indicator are ready and minimum user threshold met.",
|
||||||
"switch-to-file-tooltip" : u"Double click to switch to {}", # Filename
|
"switch-to-file-tooltip" : u"Double click to switch to {}", # Filename
|
||||||
|
"sendmessage-tooltip" : u"Send message to room",
|
||||||
|
|
||||||
# In-userlist notes (GUI)
|
# In-userlist notes (GUI)
|
||||||
"differentsize-note" : "Different size!",
|
"differentsize-note" : "Different size!",
|
||||||
@ -377,6 +382,7 @@ en = {
|
|||||||
"server-salt-argument" : "random string used to generate managed room passwords",
|
"server-salt-argument" : "random string used to generate managed room passwords",
|
||||||
"server-disable-ready-argument" : u"disable readiness feature",
|
"server-disable-ready-argument" : u"disable readiness feature",
|
||||||
"server-motd-argument": "path to file from which motd will be fetched",
|
"server-motd-argument": "path to file from which motd will be fetched",
|
||||||
|
"server-chat-argument" : "Should chat be disabled?",
|
||||||
"server-messed-up-motd-unescaped-placeholders": "Message of the Day has unescaped placeholders. All $ signs should be doubled ($$).",
|
"server-messed-up-motd-unescaped-placeholders": "Message of the Day has unescaped placeholders. All $ signs should be doubled ($$).",
|
||||||
"server-messed-up-motd-too-long": u"Message of the Day is too long - maximum of {} chars, {} given.",
|
"server-messed-up-motd-too-long": u"Message of the Day is too long - maximum of {} chars, {} given.",
|
||||||
|
|
||||||
@ -403,6 +409,7 @@ en = {
|
|||||||
"addurlstoplaylist-menu-label" : u"Add URL(s) to bottom of playlist",
|
"addurlstoplaylist-menu-label" : u"Add URL(s) to bottom of playlist",
|
||||||
"editplaylist-menu-label": u"Edit playlist",
|
"editplaylist-menu-label": u"Edit playlist",
|
||||||
|
|
||||||
|
"open-containing-folder": u"Open folder containing this file",
|
||||||
"addusersfiletoplaylist-menu-label" : u"Add {} file to playlist", # item owner indicator
|
"addusersfiletoplaylist-menu-label" : u"Add {} file to playlist", # item owner indicator
|
||||||
"addusersstreamstoplaylist-menu-label" : u"Add {} stream to playlist", # item owner indicator
|
"addusersstreamstoplaylist-menu-label" : u"Add {} stream to playlist", # item owner indicator
|
||||||
"openusersstream-menu-label" : u"Open {} stream", # [username]'s
|
"openusersstream-menu-label" : u"Open {} stream", # [username]'s
|
||||||
|
|||||||
@ -85,6 +85,7 @@ ru = {
|
|||||||
"commandlist-notification/toggle" : u"\tt - переключить статус готов/не готов к просмотру",
|
"commandlist-notification/toggle" : u"\tt - переключить статус готов/не готов к просмотру",
|
||||||
"commandlist-notification/create" : u"\tc [name] - создать управляемую комнату с таким же именем, как у текущей",
|
"commandlist-notification/create" : u"\tc [name] - создать управляемую комнату с таким же именем, как у текущей",
|
||||||
"commandlist-notification/auth" : u"\ta [password] - авторизоваться как оператор комнаты с помощью пароля",
|
"commandlist-notification/auth" : u"\ta [password] - авторизоваться как оператор комнаты с помощью пароля",
|
||||||
|
"commandlist-notification/chat" : "\tch [message] - send a chat message in a room", # TODO: Translate
|
||||||
"syncplay-version-notification" : u"Версия Syncplay: {}", # syncplay.version
|
"syncplay-version-notification" : u"Версия Syncplay: {}", # syncplay.version
|
||||||
"more-info-notification" : u"Больше информации на {}", # projectURL
|
"more-info-notification" : u"Больше информации на {}", # projectURL
|
||||||
|
|
||||||
@ -135,6 +136,7 @@ ru = {
|
|||||||
|
|
||||||
"not-supported-by-server-error" : u"Эта возможность не поддерживается сервером. Требуется сервер Syncplay {}+, вы подключены к серверу Syncplay {}.", #minVersion, serverVersion
|
"not-supported-by-server-error" : u"Эта возможность не поддерживается сервером. Требуется сервер Syncplay {}+, вы подключены к серверу Syncplay {}.", #minVersion, serverVersion
|
||||||
"shared-playlists-not-supported-by-server-error" : u"Общие списки воспроизведения могут не поддерживаться сервером. Для корректной работы требуется сервер Syncplay {}+, вы подключены к серверу Syncplay {}.", #minVersion, serverVersion
|
"shared-playlists-not-supported-by-server-error" : u"Общие списки воспроизведения могут не поддерживаться сервером. Для корректной работы требуется сервер Syncplay {}+, вы подключены к серверу Syncplay {}.", #minVersion, serverVersion
|
||||||
|
"shared-playlists-disabled-by-server-error" : "The shared playlist feature has been disabled in the server configuration. To use this feature you will need to connect to a different server.", # TODO: Translate
|
||||||
|
|
||||||
"invalid-seek-value" : u"Некорректное значение для перемотки",
|
"invalid-seek-value" : u"Некорректное значение для перемотки",
|
||||||
"invalid-offset-value" : u"Некорректное смещение",
|
"invalid-offset-value" : u"Некорректное смещение",
|
||||||
@ -251,10 +253,12 @@ ru = {
|
|||||||
"autoplay-menu-label" : u"Показывать кнопку &автовоспроизведения",
|
"autoplay-menu-label" : u"Показывать кнопку &автовоспроизведения",
|
||||||
"autoplay-guipushbuttonlabel" : u"Стартовать, когда все будут готовы",
|
"autoplay-guipushbuttonlabel" : u"Стартовать, когда все будут готовы",
|
||||||
"autoplay-minimum-label" : u"Минимум зрителей:",
|
"autoplay-minimum-label" : u"Минимум зрителей:",
|
||||||
|
"sendmessage-label" : u"Send", # TODO: Translate
|
||||||
|
|
||||||
"ready-guipushbuttonlabel" : u"Я готов",
|
"ready-guipushbuttonlabel" : u"Я готов",
|
||||||
|
|
||||||
"roomuser-heading-label" : u"Комната / Зритель",
|
"roomuser-heading-label" : u"Комната / Зритель",
|
||||||
|
|
||||||
"size-heading-label" : u"Размер",
|
"size-heading-label" : u"Размер",
|
||||||
"duration-heading-label" : u"Время",
|
"duration-heading-label" : u"Время",
|
||||||
"filename-heading-label" : u"Имя файла",
|
"filename-heading-label" : u"Имя файла",
|
||||||
@ -353,6 +357,7 @@ ru = {
|
|||||||
"ready-tooltip" : u"Показывает, готовы ли Вы к просмотру или нет.",
|
"ready-tooltip" : u"Показывает, готовы ли Вы к просмотру или нет.",
|
||||||
"autoplay-tooltip" : u"Автоматическое воспроизведение, когда все пользователи с индикаторами готовности будут готовы и присутствует достаточное число зрителей.",
|
"autoplay-tooltip" : u"Автоматическое воспроизведение, когда все пользователи с индикаторами готовности будут готовы и присутствует достаточное число зрителей.",
|
||||||
"switch-to-file-tooltip" : u"Кликните два раза для воспроизведения {}", # Filename
|
"switch-to-file-tooltip" : u"Кликните два раза для воспроизведения {}", # Filename
|
||||||
|
"sendmessage-tooltip" : u"Send message to room", # TODO: Translate
|
||||||
|
|
||||||
# In-userlist notes (GUI)
|
# In-userlist notes (GUI)
|
||||||
"differentsize-note" : u"Размер файла не совпадает!",
|
"differentsize-note" : u"Размер файла не совпадает!",
|
||||||
@ -378,6 +383,7 @@ ru = {
|
|||||||
"server-salt-argument" : u"генерировать пароли к управляемым комнатам на основании указанной строки (соли)",
|
"server-salt-argument" : u"генерировать пароли к управляемым комнатам на основании указанной строки (соли)",
|
||||||
"server-disable-ready-argument" : u"отключить статусы готов/не готов",
|
"server-disable-ready-argument" : u"отключить статусы готов/не готов",
|
||||||
"server-motd-argument" : u"путь к файлу, из которого будет извлекаться MOTD-сообщение",
|
"server-motd-argument" : u"путь к файлу, из которого будет извлекаться MOTD-сообщение",
|
||||||
|
"server-chat-argument" : "Should chat be disabled?", # TODO: Translate
|
||||||
"server-messed-up-motd-unescaped-placeholders" : u"MOTD-сообщение содержит неэкранированные спец.символы. Все знаки $ должны быть продублированы ($$).",
|
"server-messed-up-motd-unescaped-placeholders" : u"MOTD-сообщение содержит неэкранированные спец.символы. Все знаки $ должны быть продублированы ($$).",
|
||||||
"server-messed-up-motd-too-long" : u"MOTD-сообщение слишком длинное: максимальная длина - {} символ(ов), текущая длина - {} символ(ов).",
|
"server-messed-up-motd-too-long" : u"MOTD-сообщение слишком длинное: максимальная длина - {} символ(ов), текущая длина - {} символ(ов).",
|
||||||
|
|
||||||
|
|||||||
@ -22,6 +22,8 @@ class JSONCommandProtocol(LineReceiver):
|
|||||||
self.handleState(message[1])
|
self.handleState(message[1])
|
||||||
elif command == "Error":
|
elif command == "Error":
|
||||||
self.handleError(message[1])
|
self.handleError(message[1])
|
||||||
|
elif command == "Chat":
|
||||||
|
self.handleChat(message[1])
|
||||||
else:
|
else:
|
||||||
self.dropWithError(getMessage("unknown-command-server-error").format(message[1])) # TODO: log, not drop
|
self.dropWithError(getMessage("unknown-command-server-error").format(message[1])) # TODO: log, not drop
|
||||||
|
|
||||||
@ -78,10 +80,11 @@ class SyncClientProtocol(JSONCommandProtocol):
|
|||||||
version = hello["version"] if hello.has_key("version") else None
|
version = hello["version"] if hello.has_key("version") else None
|
||||||
version = hello["realversion"] if hello.has_key("realversion") else version # Used for 1.2.X compatibility
|
version = hello["realversion"] if hello.has_key("realversion") else version # Used for 1.2.X compatibility
|
||||||
motd = hello["motd"] if hello.has_key("motd") else None
|
motd = hello["motd"] if hello.has_key("motd") else None
|
||||||
return username, roomName, version, motd
|
features = hello["features"] if hello.has_key("features") else None
|
||||||
|
return username, roomName, version, motd, features
|
||||||
|
|
||||||
def handleHello(self, hello):
|
def handleHello(self, hello):
|
||||||
username, roomName, version, motd = self._extractHelloArguments(hello)
|
username, roomName, version, motd, featureList = self._extractHelloArguments(hello)
|
||||||
if not username or not roomName or not version:
|
if not username or not roomName or not version:
|
||||||
self.dropWithError(getMessage("hello-server-error").format(hello))
|
self.dropWithError(getMessage("hello-server-error").format(hello))
|
||||||
else:
|
else:
|
||||||
@ -93,7 +96,7 @@ class SyncClientProtocol(JSONCommandProtocol):
|
|||||||
self._client.ui.showMessage(getMessage("connected-successful-notification"))
|
self._client.ui.showMessage(getMessage("connected-successful-notification"))
|
||||||
self._client.connected()
|
self._client.connected()
|
||||||
self._client.sendFile()
|
self._client.sendFile()
|
||||||
self._client.setServerVersion(version)
|
self._client.setServerVersion(version, featureList)
|
||||||
|
|
||||||
def sendHello(self):
|
def sendHello(self):
|
||||||
hello = {}
|
hello = {}
|
||||||
@ -158,6 +161,9 @@ class SyncClientProtocol(JSONCommandProtocol):
|
|||||||
self.sendSet({"file": file_})
|
self.sendSet({"file": file_})
|
||||||
self.sendList()
|
self.sendList()
|
||||||
|
|
||||||
|
def sendChatMessage(self,chatMessage):
|
||||||
|
self.sendMessage({"Chat": chatMessage})
|
||||||
|
|
||||||
def handleList(self, userList):
|
def handleList(self, userList):
|
||||||
self._client.userlist.clearList()
|
self._client.userlist.clearList()
|
||||||
for room in userList.iteritems():
|
for room in userList.iteritems():
|
||||||
@ -242,6 +248,10 @@ class SyncClientProtocol(JSONCommandProtocol):
|
|||||||
"password": password
|
"password": password
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
def handleChat(self,message):
|
||||||
|
userMessage = message['message']
|
||||||
|
messageString = u"<{}> {}".format(message['username'], userMessage)
|
||||||
|
self._client.ui.showMessage(messageString)
|
||||||
|
|
||||||
def setReady(self, isReady, manuallyInitiated=True):
|
def setReady(self, isReady, manuallyInitiated=True):
|
||||||
self.sendSet({
|
self.sendSet({
|
||||||
@ -275,6 +285,7 @@ class SyncClientProtocol(JSONCommandProtocol):
|
|||||||
class SyncServerProtocol(JSONCommandProtocol):
|
class SyncServerProtocol(JSONCommandProtocol):
|
||||||
def __init__(self, factory):
|
def __init__(self, factory):
|
||||||
self._factory = factory
|
self._factory = factory
|
||||||
|
self._version = None
|
||||||
self._logged = False
|
self._logged = False
|
||||||
self.clientIgnoringOnTheFly = 0
|
self.clientIgnoringOnTheFly = 0
|
||||||
self.serverIgnoringOnTheFly = 0
|
self.serverIgnoringOnTheFly = 0
|
||||||
@ -311,6 +322,12 @@ class SyncServerProtocol(JSONCommandProtocol):
|
|||||||
def isLogged(self):
|
def isLogged(self):
|
||||||
return self._logged
|
return self._logged
|
||||||
|
|
||||||
|
def meetsMinVersion(self, version):
|
||||||
|
return self._version >= version
|
||||||
|
|
||||||
|
def getVersion(self):
|
||||||
|
return self._version
|
||||||
|
|
||||||
def _extractHelloArguments(self, hello):
|
def _extractHelloArguments(self, hello):
|
||||||
roomName = None
|
roomName = None
|
||||||
username = hello["username"] if hello.has_key("username") else None
|
username = hello["username"] if hello.has_key("username") else None
|
||||||
@ -342,10 +359,15 @@ class SyncServerProtocol(JSONCommandProtocol):
|
|||||||
else:
|
else:
|
||||||
if not self._checkPassword(serverPassword):
|
if not self._checkPassword(serverPassword):
|
||||||
return
|
return
|
||||||
|
self._version = version
|
||||||
self._factory.addWatcher(self, username, roomName)
|
self._factory.addWatcher(self, username, roomName)
|
||||||
self._logged = True
|
self._logged = True
|
||||||
self.sendHello(version)
|
self.sendHello(version)
|
||||||
|
|
||||||
|
def handleChat(self,chatMessage):
|
||||||
|
if not self._factory.disableChat:
|
||||||
|
self._factory.sendChat(self._watcher,chatMessage)
|
||||||
|
|
||||||
def setWatcher(self, watcher):
|
def setWatcher(self, watcher):
|
||||||
self._watcher = watcher
|
self._watcher = watcher
|
||||||
|
|
||||||
@ -359,6 +381,7 @@ class SyncServerProtocol(JSONCommandProtocol):
|
|||||||
hello["version"] = clientVersion # Used so 1.2.X client works on newer server
|
hello["version"] = clientVersion # Used so 1.2.X client works on newer server
|
||||||
hello["realversion"] = syncplay.version
|
hello["realversion"] = syncplay.version
|
||||||
hello["motd"] = self._factory.getMotd(userIp, username, room, clientVersion)
|
hello["motd"] = self._factory.getMotd(userIp, username, room, clientVersion)
|
||||||
|
hello["features"] = self._factory.getFeatures()
|
||||||
self.sendMessage({"Hello": hello})
|
self.sendMessage({"Hello": hello})
|
||||||
|
|
||||||
@requireLogged
|
@requireLogged
|
||||||
|
|||||||
@ -11,10 +11,11 @@ import codecs
|
|||||||
import os
|
import os
|
||||||
from string import Template
|
from string import Template
|
||||||
import argparse
|
import argparse
|
||||||
from syncplay.utils import RoomPasswordProvider, NotControlledRoom, RandomStringGenerator, meetsMinVersion, playlistIsValid
|
from syncplay.utils import RoomPasswordProvider, NotControlledRoom, RandomStringGenerator, meetsMinVersion, playlistIsValid, truncateText
|
||||||
|
|
||||||
class SyncFactory(Factory):
|
class SyncFactory(Factory):
|
||||||
def __init__(self, password='', motdFilePath=None, isolateRooms=False, salt=None, disableReady=False):
|
def __init__(self, password='', motdFilePath=None, isolateRooms=False, salt=None, disableReady=False,disableChat=False):
|
||||||
|
self.isolateRooms = isolateRooms
|
||||||
print getMessage("welcome-server-notification").format(syncplay.version)
|
print getMessage("welcome-server-notification").format(syncplay.version)
|
||||||
if password:
|
if password:
|
||||||
password = hashlib.md5(password).hexdigest()
|
password = hashlib.md5(password).hexdigest()
|
||||||
@ -25,6 +26,7 @@ class SyncFactory(Factory):
|
|||||||
self._salt = salt
|
self._salt = salt
|
||||||
self._motdFilePath = motdFilePath
|
self._motdFilePath = motdFilePath
|
||||||
self.disableReady = disableReady
|
self.disableReady = disableReady
|
||||||
|
self.disableChat = disableChat
|
||||||
if not isolateRooms:
|
if not isolateRooms:
|
||||||
self._roomManager = RoomManager()
|
self._roomManager = RoomManager()
|
||||||
else:
|
else:
|
||||||
@ -40,6 +42,14 @@ class SyncFactory(Factory):
|
|||||||
setBy = room.getSetBy()
|
setBy = room.getSetBy()
|
||||||
watcher.sendState(position, paused, doSeek, setBy, forcedUpdate)
|
watcher.sendState(position, paused, doSeek, setBy, forcedUpdate)
|
||||||
|
|
||||||
|
def getFeatures(self):
|
||||||
|
features = dict()
|
||||||
|
features["isolateRooms"] = self.isolateRooms
|
||||||
|
features["readiness"] = not self.disableReady
|
||||||
|
features["managedRooms"] = True
|
||||||
|
features["chat"] = not self.disableChat
|
||||||
|
return features
|
||||||
|
|
||||||
def getMotd(self, userIp, username, room, clientVersion):
|
def getMotd(self, userIp, username, room, clientVersion):
|
||||||
oldClient = False
|
oldClient = False
|
||||||
if constants.WARN_OLD_CLIENTS:
|
if constants.WARN_OLD_CLIENTS:
|
||||||
@ -62,11 +72,13 @@ class SyncFactory(Factory):
|
|||||||
return ""
|
return ""
|
||||||
|
|
||||||
def addWatcher(self, watcherProtocol, username, roomName):
|
def addWatcher(self, watcherProtocol, username, roomName):
|
||||||
|
roomName = truncateText(roomName, constants.MAX_ROOM_NAME_LENGTH)
|
||||||
username = self._roomManager.findFreeUsername(username)
|
username = self._roomManager.findFreeUsername(username)
|
||||||
watcher = Watcher(self, watcherProtocol, username)
|
watcher = Watcher(self, watcherProtocol, username)
|
||||||
self.setWatcherRoom(watcher, roomName, asJoin=True)
|
self.setWatcherRoom(watcher, roomName, asJoin=True)
|
||||||
|
|
||||||
def setWatcherRoom(self, watcher, roomName, asJoin=False):
|
def setWatcherRoom(self, watcher, roomName, asJoin=False):
|
||||||
|
roomName = truncateText(roomName, constants.MAX_ROOM_NAME_LENGTH)
|
||||||
self._roomManager.moveWatcher(watcher, roomName)
|
self._roomManager.moveWatcher(watcher, roomName)
|
||||||
if asJoin:
|
if asJoin:
|
||||||
self.sendJoinMessage(watcher)
|
self.sendJoinMessage(watcher)
|
||||||
@ -96,7 +108,7 @@ class SyncFactory(Factory):
|
|||||||
self._roomManager.broadcast(watcher, l)
|
self._roomManager.broadcast(watcher, l)
|
||||||
|
|
||||||
def sendJoinMessage(self, watcher):
|
def sendJoinMessage(self, watcher):
|
||||||
l = lambda w: w.sendSetting(watcher.getName(), watcher.getRoom(), None, {"joined": True}) if w != watcher else None
|
l = lambda w: w.sendSetting(watcher.getName(), watcher.getRoom(), None, {"joined": True, "version": watcher.getVersion()}) if w != watcher else None
|
||||||
self._roomManager.broadcast(watcher, l)
|
self._roomManager.broadcast(watcher, l)
|
||||||
self._roomManager.broadcastRoom(watcher, lambda w: w.sendSetReady(watcher.getName(), watcher.isReady(), False))
|
self._roomManager.broadcastRoom(watcher, lambda w: w.sendSetReady(watcher.getName(), watcher.isReady(), False))
|
||||||
|
|
||||||
@ -134,6 +146,11 @@ class SyncFactory(Factory):
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
self._roomManager.broadcastRoom(watcher, lambda w: w.sendControlledRoomAuthStatus(False, watcher.getName(), room._name))
|
self._roomManager.broadcastRoom(watcher, lambda w: w.sendControlledRoomAuthStatus(False, watcher.getName(), room._name))
|
||||||
|
|
||||||
|
def sendChat(self,watcher,message):
|
||||||
|
message = truncateText(message, constants.MAX_CHAT_MESSAGE_LENGTH)
|
||||||
|
messageDict={"message":message,"username" : watcher.getName()}
|
||||||
|
self._roomManager.broadcastRoom(watcher, lambda w: w.sendChatMessage(messageDict))
|
||||||
|
|
||||||
def setReady(self, watcher, isReady, manuallyInitiated=True):
|
def setReady(self, watcher, isReady, manuallyInitiated=True):
|
||||||
watcher.setReady(isReady)
|
watcher.setReady(isReady)
|
||||||
self._roomManager.broadcastRoom(watcher, lambda w: w.sendSetReady(watcher.getName(), watcher.isReady(), manuallyInitiated))
|
self._roomManager.broadcastRoom(watcher, lambda w: w.sendSetReady(watcher.getName(), watcher.isReady(), manuallyInitiated))
|
||||||
@ -178,6 +195,7 @@ class RoomManager(object):
|
|||||||
return watchers
|
return watchers
|
||||||
|
|
||||||
def moveWatcher(self, watcher, roomName):
|
def moveWatcher(self, watcher, roomName):
|
||||||
|
roomName = truncateText(roomName, constants.MAX_ROOM_NAME_LENGTH)
|
||||||
self.removeWatcher(watcher)
|
self.removeWatcher(watcher)
|
||||||
room = self._getRoom(roomName)
|
room = self._getRoom(roomName)
|
||||||
room.addWatcher(watcher)
|
room.addWatcher(watcher)
|
||||||
@ -204,6 +222,7 @@ class RoomManager(object):
|
|||||||
del self._rooms[room.getName()]
|
del self._rooms[room.getName()]
|
||||||
|
|
||||||
def findFreeUsername(self, username):
|
def findFreeUsername(self, username):
|
||||||
|
username = truncateText(username,constants.MAX_USERNAME_LENGTH)
|
||||||
allnames = []
|
allnames = []
|
||||||
for room in self._rooms.itervalues():
|
for room in self._rooms.itervalues():
|
||||||
for watcher in room.getWatchers():
|
for watcher in room.getWatchers():
|
||||||
@ -378,6 +397,9 @@ class Watcher(object):
|
|||||||
reactor.callLater(0.1, self._scheduleSendState)
|
reactor.callLater(0.1, self._scheduleSendState)
|
||||||
|
|
||||||
def setFile(self, file_):
|
def setFile(self, file_):
|
||||||
|
print file_
|
||||||
|
if file_ and file_.has_key("name"):
|
||||||
|
file_["name"] = truncateText(file_["name"],constants.MAX_FILENAME_LENGTH)
|
||||||
self._file = file_
|
self._file = file_
|
||||||
self._server.sendFileUpdate(self)
|
self._server.sendFileUpdate(self)
|
||||||
|
|
||||||
@ -403,6 +425,9 @@ class Watcher(object):
|
|||||||
def getName(self):
|
def getName(self):
|
||||||
return self._name
|
return self._name
|
||||||
|
|
||||||
|
def getVersion(self):
|
||||||
|
return self._connector.getVersion()
|
||||||
|
|
||||||
def getFile(self):
|
def getFile(self):
|
||||||
return self._file
|
return self._file
|
||||||
|
|
||||||
@ -427,6 +452,10 @@ class Watcher(object):
|
|||||||
def sendControlledRoomAuthStatus(self, success, username, room):
|
def sendControlledRoomAuthStatus(self, success, username, room):
|
||||||
self._connector.sendControlledRoomAuthStatus(success, username, room)
|
self._connector.sendControlledRoomAuthStatus(success, username, room)
|
||||||
|
|
||||||
|
def sendChatMessage(self,message):
|
||||||
|
if self._connector.meetsMinVersion(constants.CHAT_MIN_VERSION):
|
||||||
|
self._connector.sendMessage({"Chat" : message})
|
||||||
|
|
||||||
def sendSetReady(self, username, isReady, manuallyInitiated=True):
|
def sendSetReady(self, username, isReady, manuallyInitiated=True):
|
||||||
self._connector.sendSetReady(username, isReady, manuallyInitiated)
|
self._connector.sendSetReady(username, isReady, manuallyInitiated)
|
||||||
|
|
||||||
@ -507,5 +536,6 @@ class ConfigurationGetter(object):
|
|||||||
self._argparser.add_argument('--password', metavar='password', type=str, nargs='?', help=getMessage("server-password-argument"))
|
self._argparser.add_argument('--password', metavar='password', type=str, nargs='?', help=getMessage("server-password-argument"))
|
||||||
self._argparser.add_argument('--isolate-rooms', action='store_true', help=getMessage("server-isolate-room-argument"))
|
self._argparser.add_argument('--isolate-rooms', action='store_true', help=getMessage("server-isolate-room-argument"))
|
||||||
self._argparser.add_argument('--disable-ready', action='store_true', help=getMessage("server-disable-ready-argument"))
|
self._argparser.add_argument('--disable-ready', action='store_true', help=getMessage("server-disable-ready-argument"))
|
||||||
|
self._argparser.add_argument('--disable-chat', action='store_true', help=getMessage("server-chat-argument"))
|
||||||
self._argparser.add_argument('--salt', metavar='salt', type=str, nargs='?', help=getMessage("server-salt-argument"))
|
self._argparser.add_argument('--salt', metavar='salt', type=str, nargs='?', help=getMessage("server-salt-argument"))
|
||||||
self._argparser.add_argument('--motd-file', metavar='file', type=str, nargs='?', help=getMessage("server-motd-argument"))
|
self._argparser.add_argument('--motd-file', metavar='file', type=str, nargs='?', help=getMessage("server-motd-argument"))
|
||||||
|
|||||||
@ -542,6 +542,9 @@ class ConfigDialog(QtGui.QDialog):
|
|||||||
self.defaultroomLabel.setObjectName("room")
|
self.defaultroomLabel.setObjectName("room")
|
||||||
self.defaultroomTextbox.setObjectName("room")
|
self.defaultroomTextbox.setObjectName("room")
|
||||||
|
|
||||||
|
self.usernameTextbox.setMaxLength(constants.MAX_USERNAME_LENGTH)
|
||||||
|
self.defaultroomTextbox.setMaxLength(constants.MAX_ROOM_NAME_LENGTH)
|
||||||
|
|
||||||
self.connectionSettingsLayout = QtGui.QGridLayout()
|
self.connectionSettingsLayout = QtGui.QGridLayout()
|
||||||
self.connectionSettingsLayout.addWidget(self.hostLabel, 0, 0)
|
self.connectionSettingsLayout.addWidget(self.hostLabel, 0, 0)
|
||||||
self.connectionSettingsLayout.addWidget(self.hostCombobox, 0, 1)
|
self.connectionSettingsLayout.addWidget(self.hostCombobox, 0, 1)
|
||||||
|
|||||||
@ -86,6 +86,9 @@ class ConsoleUI(threading.Thread):
|
|||||||
def fileSwitchFoundFiles(self):
|
def fileSwitchFoundFiles(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def setFeatures(self, featureList):
|
||||||
|
pass
|
||||||
|
|
||||||
def showMessage(self, message, noTimestamp=False):
|
def showMessage(self, message, noTimestamp=False):
|
||||||
message = message.encode(sys.stdout.encoding, 'replace')
|
message = message.encode(sys.stdout.encoding, 'replace')
|
||||||
if noTimestamp:
|
if noTimestamp:
|
||||||
@ -143,6 +146,9 @@ class ConsoleUI(threading.Thread):
|
|||||||
self._syncplayClient.playerPositionBeforeLastSeek = tmp_pos
|
self._syncplayClient.playerPositionBeforeLastSeek = tmp_pos
|
||||||
elif command.group('command') in constants.COMMANDS_LIST:
|
elif command.group('command') in constants.COMMANDS_LIST:
|
||||||
self._syncplayClient.getUserList()
|
self._syncplayClient.getUserList()
|
||||||
|
elif command.group('command') in constants.COMMANDS_CHAT:
|
||||||
|
message= command.group('parameter')
|
||||||
|
self._syncplayClient.sendChat(message)
|
||||||
elif command.group('command') in constants.COMMANDS_PAUSE:
|
elif command.group('command') in constants.COMMANDS_PAUSE:
|
||||||
self._syncplayClient.setPaused(not self._syncplayClient.getPlayerPaused())
|
self._syncplayClient.setPaused(not self._syncplayClient.getPlayerPaused())
|
||||||
elif command.group('command') in constants.COMMANDS_ROOM:
|
elif command.group('command') in constants.COMMANDS_ROOM:
|
||||||
@ -181,6 +187,7 @@ class ConsoleUI(threading.Thread):
|
|||||||
self.showMessage(getMessage("commandlist-notification/toggle"), True)
|
self.showMessage(getMessage("commandlist-notification/toggle"), True)
|
||||||
self.showMessage(getMessage("commandlist-notification/create"), True)
|
self.showMessage(getMessage("commandlist-notification/create"), True)
|
||||||
self.showMessage(getMessage("commandlist-notification/auth"), True)
|
self.showMessage(getMessage("commandlist-notification/auth"), True)
|
||||||
|
self.showMessage(getMessage("commandlist-notification/chat"), True)
|
||||||
self.showMessage(getMessage("syncplay-version-notification").format(syncplay.version), True)
|
self.showMessage(getMessage("syncplay-version-notification").format(syncplay.version), True)
|
||||||
self.showMessage(getMessage("more-info-notification").format(syncplay.projectURL), True)
|
self.showMessage(getMessage("more-info-notification").format(syncplay.projectURL), True)
|
||||||
|
|
||||||
|
|||||||
@ -327,11 +327,24 @@ class MainWindow(QtGui.QMainWindow):
|
|||||||
# TODO: Prompt user
|
# TODO: Prompt user
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def setFeatures(self, featureList):
|
||||||
|
if not featureList["readiness"]:
|
||||||
|
self.readyPushButton.setEnabled(False)
|
||||||
|
if not featureList["chat"]:
|
||||||
|
self.chatFrame.setEnabled(False)
|
||||||
|
if not featureList["sharedPlaylists"]:
|
||||||
|
self.playlistGroup.setEnabled(False)
|
||||||
|
|
||||||
def showMessage(self, message, noTimestamp=False):
|
def showMessage(self, message, noTimestamp=False):
|
||||||
message = unicode(message)
|
message = unicode(message)
|
||||||
message = message.replace(u"&", u"&").replace(u'"', u""").replace(u"<", u"<").replace(">", u">")
|
username = None
|
||||||
message = message.replace(u"<", u"<span style=\"{}\"><".format(constants.STYLE_USERNAME))
|
messageWithUsername = re.match(constants.MESSAGE_WITH_USERNAME_REGEX, message, re.UNICODE)
|
||||||
message = message.replace(u">", u"></span>")
|
if messageWithUsername:
|
||||||
|
username = messageWithUsername.group("username")
|
||||||
|
message = messageWithUsername.group("message")
|
||||||
|
message = message.replace(u"&", u"&").replace(u'"', u""").replace(u"<", u"<").replace(u">", u">")
|
||||||
|
if username:
|
||||||
|
message = constants.STYLE_USER_MESSAGE.format(constants.STYLE_USERNAME, username, message)
|
||||||
message = message.replace(u"\n", u"<br />")
|
message = message.replace(u"\n", u"<br />")
|
||||||
if noTimestamp:
|
if noTimestamp:
|
||||||
self.newMessage(u"{}<br />".format(message))
|
self.newMessage(u"{}<br />".format(message))
|
||||||
@ -564,6 +577,10 @@ class MainWindow(QtGui.QMainWindow):
|
|||||||
if self._syncplayClient.isUntrustedTrustableURI(filename):
|
if self._syncplayClient.isUntrustedTrustableURI(filename):
|
||||||
domain = utils.getDomainFromURL(filename)
|
domain = utils.getDomainFromURL(filename)
|
||||||
menu.addAction(QtGui.QPixmap(resourcespath + u"shield_add.png"),getMessage("addtrusteddomain-menu-label").format(domain), lambda: self.addTrustedDomain(domain))
|
menu.addAction(QtGui.QPixmap(resourcespath + u"shield_add.png"),getMessage("addtrusteddomain-menu-label").format(domain), lambda: self.addTrustedDomain(domain))
|
||||||
|
|
||||||
|
if not isURL(filename):
|
||||||
|
path = self._syncplayClient.fileSwitch.findFilepath(filename)
|
||||||
|
menu.addAction(QtGui.QPixmap(resourcespath + u"film_folder_edit.png"), getMessage('open-containing-folder'), lambda: utils.open_system_file_browser(path))
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
menu.exec_(self.listTreeView.viewport().mapToGlobal(position))
|
menu.exec_(self.listTreeView.viewport().mapToGlobal(position))
|
||||||
@ -1025,6 +1042,11 @@ class MainWindow(QtGui.QMainWindow):
|
|||||||
self._syncplayClient.playlist.changePlaylist(newPlaylist)
|
self._syncplayClient.playlist.changePlaylist(newPlaylist)
|
||||||
self._syncplayClient.fileSwitch.updateInfo()
|
self._syncplayClient.fileSwitch.updateInfo()
|
||||||
|
|
||||||
|
def sendChatMessage(self):
|
||||||
|
if self.chatInput.text() <> "":
|
||||||
|
self._syncplayClient.sendChat(self.chatInput.text())
|
||||||
|
self.chatInput.setText("")
|
||||||
|
|
||||||
def addTopLayout(self, window):
|
def addTopLayout(self, window):
|
||||||
window.topSplit = self.topSplitter(Qt.Horizontal, self)
|
window.topSplit = self.topSplitter(Qt.Horizontal, self)
|
||||||
|
|
||||||
@ -1040,12 +1062,29 @@ class MainWindow(QtGui.QMainWindow):
|
|||||||
window.outputbox.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
|
window.outputbox.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
|
||||||
|
|
||||||
window.outputlabel = QtGui.QLabel(getMessage("notifications-heading-label"))
|
window.outputlabel = QtGui.QLabel(getMessage("notifications-heading-label"))
|
||||||
|
window.chatInput = QtGui.QLineEdit()
|
||||||
|
window.chatInput.setMaxLength(constants.MAX_CHAT_MESSAGE_LENGTH)
|
||||||
|
window.chatInput.returnPressed.connect(self.sendChatMessage)
|
||||||
|
window.chatButton = QtGui.QPushButton(QtGui.QIcon(self.resourcespath + 'email_go.png'),
|
||||||
|
getMessage("sendmessage-label"))
|
||||||
|
window.chatButton.pressed.connect(self.sendChatMessage)
|
||||||
|
window.chatLayout = QtGui.QHBoxLayout()
|
||||||
|
window.chatFrame = QtGui.QFrame()
|
||||||
|
window.chatFrame.setLayout(self.chatLayout)
|
||||||
|
window.chatFrame.setContentsMargins(0,0,0,0)
|
||||||
|
window.chatFrame.setSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Minimum)
|
||||||
|
window.chatLayout.setContentsMargins(0,0,0,0)
|
||||||
|
self.chatButton.setToolTip(getMessage("sendmessage-tooltip"))
|
||||||
|
window.chatLayout.addWidget(window.chatInput)
|
||||||
|
window.chatLayout.addWidget(window.chatButton)
|
||||||
|
window.chatFrame.setMaximumHeight(window.chatFrame.sizeHint().height())
|
||||||
window.outputFrame = QtGui.QFrame()
|
window.outputFrame = QtGui.QFrame()
|
||||||
window.outputFrame.setLineWidth(0)
|
window.outputFrame.setLineWidth(0)
|
||||||
window.outputFrame.setMidLineWidth(0)
|
window.outputFrame.setMidLineWidth(0)
|
||||||
window.outputLayout.setContentsMargins(0, 0, 0, 0)
|
window.outputLayout.setContentsMargins(0, 0, 0, 0)
|
||||||
window.outputLayout.addWidget(window.outputlabel)
|
window.outputLayout.addWidget(window.outputlabel)
|
||||||
window.outputLayout.addWidget(window.outputbox)
|
window.outputLayout.addWidget(window.outputbox)
|
||||||
|
window.outputLayout.addWidget(window.chatFrame)
|
||||||
window.outputFrame.setLayout(window.outputLayout)
|
window.outputFrame.setLayout(window.outputLayout)
|
||||||
|
|
||||||
window.listLayout = QtGui.QVBoxLayout()
|
window.listLayout = QtGui.QVBoxLayout()
|
||||||
@ -1079,6 +1118,7 @@ class MainWindow(QtGui.QMainWindow):
|
|||||||
window.listLayout.addWidget(window.listSplit)
|
window.listLayout.addWidget(window.listSplit)
|
||||||
|
|
||||||
window.roomInput = QtGui.QLineEdit()
|
window.roomInput = QtGui.QLineEdit()
|
||||||
|
window.roomInput.setMaxLength(constants.MAX_ROOM_NAME_LENGTH)
|
||||||
window.roomInput.returnPressed.connect(self.joinRoom)
|
window.roomInput.returnPressed.connect(self.joinRoom)
|
||||||
window.roomButton = QtGui.QPushButton(QtGui.QIcon(self.resourcespath + 'door_in.png'),
|
window.roomButton = QtGui.QPushButton(QtGui.QIcon(self.resourcespath + 'door_in.png'),
|
||||||
getMessage("joinroom-label"))
|
getMessage("joinroom-label"))
|
||||||
|
|||||||
@ -11,6 +11,9 @@ import random
|
|||||||
import string
|
import string
|
||||||
import urllib
|
import urllib
|
||||||
import ast
|
import ast
|
||||||
|
import unicodedata
|
||||||
|
import platform
|
||||||
|
import subprocess
|
||||||
|
|
||||||
folderSearchEnabled = True
|
folderSearchEnabled = True
|
||||||
|
|
||||||
@ -160,6 +163,22 @@ def blackholeStdoutForFrozenWindow():
|
|||||||
sys.stdout = Blackhole()
|
sys.stdout = Blackhole()
|
||||||
del Blackhole
|
del Blackhole
|
||||||
|
|
||||||
|
def truncateText(unicodeText, maxLength):
|
||||||
|
try:
|
||||||
|
unicodeText = unicodedata.normalize('NFC', unicodeText)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
maxSaneLength= maxLength*5
|
||||||
|
if len(unicodeText) > maxSaneLength:
|
||||||
|
unicodeText = unicode(unicodeText.encode("utf-8")[:maxSaneLength], "utf-8", errors="ignore")
|
||||||
|
while len(unicodeText) > maxLength:
|
||||||
|
unicodeText = unicode(unicodeText.encode("utf-8")[:-1], "utf-8", errors="ignore")
|
||||||
|
return unicodeText
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return ""
|
||||||
|
|
||||||
# Relate to file hashing / difference checking:
|
# Relate to file hashing / difference checking:
|
||||||
|
|
||||||
def stripfilename(filename, stripURL):
|
def stripfilename(filename, stripURL):
|
||||||
@ -202,6 +221,11 @@ def hashFilesize(size):
|
|||||||
return hashlib.sha256(str(size)).hexdigest()[:12]
|
return hashlib.sha256(str(size)).hexdigest()[:12]
|
||||||
|
|
||||||
def sameHashed(string1raw, string1hashed, string2raw, string2hashed):
|
def sameHashed(string1raw, string1hashed, string2raw, string2hashed):
|
||||||
|
try:
|
||||||
|
if string1raw.lower() == string2raw.lower():
|
||||||
|
return True
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
if string1raw == string2raw:
|
if string1raw == string2raw:
|
||||||
return True
|
return True
|
||||||
elif string1raw == string2hashed:
|
elif string1raw == string2hashed:
|
||||||
@ -289,6 +313,17 @@ def getDomainFromURL(URL):
|
|||||||
except:
|
except:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def open_system_file_browser(path):
|
||||||
|
if isURL(path):
|
||||||
|
return
|
||||||
|
path = os.path.dirname(path)
|
||||||
|
if platform.system() == "Windows":
|
||||||
|
os.startfile(path)
|
||||||
|
elif platform.system() == "Darwin":
|
||||||
|
subprocess.Popen(["open", path])
|
||||||
|
else:
|
||||||
|
subprocess.Popen(["xdg-open", path])
|
||||||
|
|
||||||
def getListOfPublicServers():
|
def getListOfPublicServers():
|
||||||
try:
|
try:
|
||||||
import urllib, syncplay, sys, messages, json
|
import urllib, syncplay, sys, messages, json
|
||||||
|
|||||||
@ -19,6 +19,5 @@ from syncplay.server import SyncFactory, ConfigurationGetter
|
|||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
argsGetter = ConfigurationGetter()
|
argsGetter = ConfigurationGetter()
|
||||||
args = argsGetter.getConfiguration()
|
args = argsGetter.getConfiguration()
|
||||||
|
reactor.listenTCP(int(args.port), SyncFactory(args.password, args.motd_file, args.isolate_rooms, args.salt, args.disable_ready,args.disable_chat))
|
||||||
reactor.listenTCP(int(args.port), SyncFactory(args.password, args.motd_file, args.isolate_rooms, args.salt, args.disable_ready))
|
|
||||||
reactor.run()
|
reactor.run()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user