diff --git a/buildPy2exe.py b/buildPy2exe.py index c59729a..5682c77 100644 --- a/buildPy2exe.py +++ b/buildPy2exe.py @@ -661,6 +661,7 @@ guiIcons = ['resources/accept.png', 'resources/arrow_undo.png', 'resources/clock 'resources/film_edit.png', 'resources/shield_edit.png', 'resources/shield_add.png', + 'resources/email_go.png', 'resources/world_add.png', 'resources/film_add.png', 'resources/delete.png', 'resources/spinner.mng' ] resources = ["resources/icon.ico", "resources/syncplay.png"] diff --git a/resources/email_go.png b/resources/email_go.png new file mode 100644 index 0000000..4a6c5d3 Binary files /dev/null and b/resources/email_go.png differ diff --git a/syncplay/__init__.py b/syncplay/__init__.py index 1325692..1d40d4f 100644 --- a/syncplay/__init__.py +++ b/syncplay/__init__.py @@ -1,4 +1,4 @@ -version = '1.4.0' +version = '1.5.0' milestone = 'Yoitsu' release_number = '36' projectURL = 'http://syncplay.pl/' diff --git a/syncplay/client.py b/syncplay/client.py index 40a44c3..fc57f6f 100644 --- a/syncplay/client.py +++ b/syncplay/client.py @@ -71,6 +71,8 @@ class SyncplayClient(object): self.lastControlPasswordAttempt = None self.serverVersion = "0.0.0" + self.serverFeatures = {} + self.lastRewindTime = None self.lastLeftTime = 0 self.lastPausedOnLeaveTime = None @@ -201,7 +203,7 @@ class SyncplayClient(object): 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: 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\ not (not self.playlist.notJustChangedPlaylist() and abs(position - currentLength ) < constants.PLAYLIST_LOAD_NEXT_FILE_TIME_FROM_END_THRESHOLD): pauseChange = self._toggleReady(pauseChange, paused) @@ -532,13 +534,25 @@ class SyncplayClient(object): size = 0 return filename, size - def setServerVersion(self, version): + def setServerVersion(self, version, featureList): 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): 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): if self.userlist.currentUser.file: @@ -571,7 +585,11 @@ class SyncplayClient(object): self.userlist.currentUser.room = roomName if resetAutoplay: self.resetAutoPlayState() - + + def sendChat(self,message): + if self._protocol and self._protocol.logged: + self._protocol.sendChatMessage(message) + def sendRoom(self): room = self.userlist.currentUser.room if self._protocol and self._protocol.logged and room: @@ -590,7 +608,11 @@ class SyncplayClient(object): return self._protocol and self._protocol.logged and self.userlist.currentUser.room 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): readyState = self._config['readyAtStart'] if self.userlist.currentUser.isReady() is None else self.userlist.currentUser.isReady() @@ -1025,13 +1047,12 @@ class SyncplayUserlist(object): self._roomUsersChanged = True 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): return False elif self.onlyUserInRoomWhoSupportsReadiness(): return False else: - return True + return self._client.serverFeatures["readiness"] def isRoomSame(self, room): if room and self.currentUser.room and self.currentUser.room == room: @@ -1314,6 +1335,9 @@ class UiManager(object): def fileSwitchFoundFiles(self): self.__ui.fileSwitchFoundFiles() + def setFeatures(self, featureList): + self.__ui.setFeatures(featureList) + def showDebugMessage(self, message): if constants.DEBUG_MODE and message.rstrip(): sys.stderr.write("{}{}\n".format(time.strftime(constants.UI_TIME_FORMAT, time.localtime()),message.rstrip())) diff --git a/syncplay/constants.py b/syncplay/constants.py index 0ac95d5..2ec7783 100644 --- a/syncplay/constants.py +++ b/syncplay/constants.py @@ -67,6 +67,7 @@ FILENAME_STRIP_REGEX = u"[-~_\.\[\](): ]" CONTROL_PASSWORD_STRIP_REGEX = u"[^a-zA-Z0-9\-]" ROOM_NAME_STRIP_REGEX = u"^(\+)(?P.*)(:)(\w{12})$" COMMANDS_UNDO = ["u", "undo", "revert"] +COMMANDS_CHAT = ["ch","chat"] COMMANDS_LIST = ["l", "list", "users"] COMMANDS_PAUSE = ["p", "play", "pause"] COMMANDS_ROOM = ["r", "room"] @@ -82,6 +83,8 @@ MPV_UNRESPONSIVE_THRESHOLD = 60.0 CONTROLLED_ROOMS_MIN_VERSION = "1.3.0" USER_READY_MIN_VERSION = "1.3.0" SHARED_PLAYLIST_MIN_VERSION = "1.4.0" +CHAT_MIN_VERSION = "1.5.0" +FEATURE_LIST_MIN_VERSION = "1.5.0" MPC_PATHS = [ r"c:\program files (x86)\mpc-hc\mpc-hc.exe", r"c:\program files\mpc-hc\mpc-hc.exe", diff --git a/syncplay/messages_de.py b/syncplay/messages_de.py index 3d1072d..92da3aa 100644 --- a/syncplay/messages_de.py +++ b/syncplay/messages_de.py @@ -85,6 +85,7 @@ de = { "commandlist-notification/toggle" : u"\tt - Bereitschaftsanzeige umschalten", "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/chat" : "\tch [message] - send a chat message in a room", # TODO: Translate "syncplay-version-notification" : u"Syncplay Version: {}", # syncplay.version "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 "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-offset-value" : u"Ungültiger Offset-Wert", @@ -249,6 +251,8 @@ de = { "autoplay-guipushbuttonlabel" : u"Automatisch abspielen wenn alle bereit sind", "autoplay-minimum-label" : u"Minimum an Nutzern:", + "sendmessage-label" : u"Send", # TODO: Translate + "ready-guipushbuttonlabel" : u"Ich bin bereit den Film anzuschauen!", "roomuser-heading-label" : u"Raum / Benutzer", @@ -353,6 +357,7 @@ de = { "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.", "switch-to-file-tooltip" : u"Doppelklicken um zu {} zu wechseln", # Filename + "sendmessage-tooltip" : u"Send message to room", # TODO: Translate # In-userlist notes (GUI) "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-disable-ready-argument" : u"Bereitschaftsfeature deaktivieren", "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-too-long": u"Die Nachricht des Tages ist zu lang - Maximal {} Zeichen, aktuell {}.", diff --git a/syncplay/messages_en.py b/syncplay/messages_en.py index 316837a..405eae3 100644 --- a/syncplay/messages_en.py +++ b/syncplay/messages_en.py @@ -85,6 +85,7 @@ en = { "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/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 "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 "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-offset-value" : u"Invalid offset value", @@ -249,6 +251,8 @@ en = { "autoplay-guipushbuttonlabel" : u"Play when all ready", "autoplay-minimum-label" : u"Min users:", + "sendmessage-label" : u"Send", + "ready-guipushbuttonlabel" : u"I'm ready to watch!", "roomuser-heading-label" : "Room / User", @@ -351,6 +355,7 @@ en = { "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.", "switch-to-file-tooltip" : u"Double click to switch to {}", # Filename + "sendmessage-tooltip" : u"Send message to room", # In-userlist notes (GUI) "differentsize-note" : "Different size!", @@ -377,6 +382,7 @@ en = { "server-salt-argument" : "random string used to generate managed room passwords", "server-disable-ready-argument" : u"disable readiness feature", "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-too-long": u"Message of the Day is too long - maximum of {} chars, {} given.", diff --git a/syncplay/messages_ru.py b/syncplay/messages_ru.py index 50e36c4..720711c 100644 --- a/syncplay/messages_ru.py +++ b/syncplay/messages_ru.py @@ -85,6 +85,7 @@ ru = { "commandlist-notification/toggle" : u"\tt - переключить статус готов/не готов к просмотру", "commandlist-notification/create" : u"\tc [name] - создать управляемую комнату с таким же именем, как у текущей", "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 "more-info-notification" : u"Больше информации на {}", # projectURL @@ -135,6 +136,7 @@ ru = { "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-offset-value" : u"Некорректное смещение", @@ -242,6 +244,7 @@ ru = { "contact-label" : u"Есть идея, нашли ошибку или хотите оставить отзыв? Пишите на dev@syncplay.pl, в IRC канал #Syncplay на irc.freenode.net или задавайте вопросы через GitHub. Кроме того, заходите на www.syncplay.pl за инорфмацией, помощью и обновлениями!", "joinroom-label" : u"Зайти в комнату", + "joinroom-menu-label" : u"Зайти в комнату {}", "seektime-menu-label" : u"Пере&мотать", "undoseek-menu-label" : u"&Отменить перемотку", @@ -251,10 +254,13 @@ ru = { "autoplay-menu-label" : u"Показывать кнопку &автовоспроизведения", "autoplay-guipushbuttonlabel" : u"Стартовать, когда все будут готовы", "autoplay-minimum-label" : u"Минимум зрителей:", + + "sendmessage-label" : u"Send", # TODO: Translate "ready-guipushbuttonlabel" : u"Я готов", "roomuser-heading-label" : u"Комната / Зритель", + "size-heading-label" : u"Размер", "duration-heading-label" : u"Время", "filename-heading-label" : u"Имя файла", @@ -353,6 +359,7 @@ ru = { "ready-tooltip" : u"Показывает, готовы ли Вы к просмотру или нет.", "autoplay-tooltip" : u"Автоматическое воспроизведение, когда все пользователи с индикаторами готовности будут готовы и присутствует достаточное число зрителей.", "switch-to-file-tooltip" : u"Кликните два раза для воспроизведения {}", # Filename + "sendmessage-tooltip" : u"Send message to room", # TODO: Translate # In-userlist notes (GUI) "differentsize-note" : u"Размер файла не совпадает!", @@ -378,6 +385,7 @@ ru = { "server-salt-argument" : u"генерировать пароли к управляемым комнатам на основании указанной строки (соли)", "server-disable-ready-argument" : u"отключить статусы готов/не готов", "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-too-long" : u"MOTD-сообщение слишком длинное: максимальная длина - {} символ(ов), текущая длина - {} символ(ов).", diff --git a/syncplay/protocols.py b/syncplay/protocols.py index 2eeafe8..ddba3f0 100644 --- a/syncplay/protocols.py +++ b/syncplay/protocols.py @@ -22,6 +22,8 @@ class JSONCommandProtocol(LineReceiver): self.handleState(message[1]) elif command == "Error": self.handleError(message[1]) + elif command == "Chat": + self.handleChat(message[1]) else: 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["realversion"] if hello.has_key("realversion") else version # Used for 1.2.X compatibility 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): - username, roomName, version, motd = self._extractHelloArguments(hello) + username, roomName, version, motd, featureList = self._extractHelloArguments(hello) if not username or not roomName or not version: self.dropWithError(getMessage("hello-server-error").format(hello)) else: @@ -93,7 +96,7 @@ class SyncClientProtocol(JSONCommandProtocol): self._client.ui.showMessage(getMessage("connected-successful-notification")) self._client.connected() self._client.sendFile() - self._client.setServerVersion(version) + self._client.setServerVersion(version, featureList) def sendHello(self): hello = {} @@ -158,6 +161,9 @@ class SyncClientProtocol(JSONCommandProtocol): self.sendSet({"file": file_}) self.sendList() + def sendChatMessage(self,chatMessage): + self.sendMessage({"Chat": chatMessage}) + def handleList(self, userList): self._client.userlist.clearList() for room in userList.iteritems(): @@ -242,6 +248,11 @@ class SyncClientProtocol(JSONCommandProtocol): "password": password } }) + def handleChat(self,message): + userMessage = message['message'].replace(u"<",u"<<").replace(u">",u">>") + messageString = u"<{}> {}".format(message['username'], userMessage) + self._client.ui.showMessage(messageString) + #TODO def setReady(self, isReady, manuallyInitiated=True): self.sendSet({ @@ -275,6 +286,7 @@ class SyncClientProtocol(JSONCommandProtocol): class SyncServerProtocol(JSONCommandProtocol): def __init__(self, factory): self._factory = factory + self._version = None self._logged = False self.clientIgnoringOnTheFly = 0 self.serverIgnoringOnTheFly = 0 @@ -311,6 +323,12 @@ class SyncServerProtocol(JSONCommandProtocol): def isLogged(self): return self._logged + def meetsMinVersion(self, version): + return self._version >= version + + def getVersion(self): + return self._version + def _extractHelloArguments(self, hello): roomName = None username = hello["username"] if hello.has_key("username") else None @@ -342,10 +360,15 @@ class SyncServerProtocol(JSONCommandProtocol): else: if not self._checkPassword(serverPassword): return + self._version = version self._factory.addWatcher(self, username, roomName) self._logged = True self.sendHello(version) + def handleChat(self,chatMessage): + if not self._factory.disableChat: + self._factory.sendChat(self._watcher,chatMessage) + def setWatcher(self, watcher): self._watcher = watcher @@ -359,6 +382,7 @@ class SyncServerProtocol(JSONCommandProtocol): hello["version"] = clientVersion # Used so 1.2.X client works on newer server hello["realversion"] = syncplay.version hello["motd"] = self._factory.getMotd(userIp, username, room, clientVersion) + hello["features"] = self._factory.getFeatures() self.sendMessage({"Hello": hello}) @requireLogged diff --git a/syncplay/server.py b/syncplay/server.py index 5acb09c..a6f9d70 100644 --- a/syncplay/server.py +++ b/syncplay/server.py @@ -14,7 +14,8 @@ import argparse from syncplay.utils import RoomPasswordProvider, NotControlledRoom, RandomStringGenerator, meetsMinVersion, playlistIsValid 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) if password: password = hashlib.md5(password).hexdigest() @@ -25,6 +26,7 @@ class SyncFactory(Factory): self._salt = salt self._motdFilePath = motdFilePath self.disableReady = disableReady + self.disableChat = disableChat if not isolateRooms: self._roomManager = RoomManager() else: @@ -40,6 +42,14 @@ class SyncFactory(Factory): setBy = room.getSetBy() 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): oldClient = False if constants.WARN_OLD_CLIENTS: @@ -96,7 +106,7 @@ class SyncFactory(Factory): self._roomManager.broadcast(watcher, l) 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.broadcastRoom(watcher, lambda w: w.sendSetReady(watcher.getName(), watcher.isReady(), False)) @@ -134,6 +144,10 @@ class SyncFactory(Factory): except ValueError: self._roomManager.broadcastRoom(watcher, lambda w: w.sendControlledRoomAuthStatus(False, watcher.getName(), room._name)) + def sendChat(self,watcher,message): + messageDict={"message":message,"username" : watcher.getName()} + self._roomManager.broadcastRoom(watcher, lambda w: w.sendChatMessage(messageDict)) + def setReady(self, watcher, isReady, manuallyInitiated=True): watcher.setReady(isReady) self._roomManager.broadcastRoom(watcher, lambda w: w.sendSetReady(watcher.getName(), watcher.isReady(), manuallyInitiated)) @@ -403,6 +417,9 @@ class Watcher(object): def getName(self): return self._name + def getVersion(self): + return self._connector.getVersion() + def getFile(self): return self._file @@ -427,6 +444,10 @@ class Watcher(object): def sendControlledRoomAuthStatus(self, 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): self._connector.sendSetReady(username, isReady, manuallyInitiated) @@ -507,5 +528,6 @@ class ConfigurationGetter(object): 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('--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('--motd-file', metavar='file', type=str, nargs='?', help=getMessage("server-motd-argument")) diff --git a/syncplay/ui/consoleUI.py b/syncplay/ui/consoleUI.py index 242482e..d5af043 100644 --- a/syncplay/ui/consoleUI.py +++ b/syncplay/ui/consoleUI.py @@ -86,6 +86,9 @@ class ConsoleUI(threading.Thread): def fileSwitchFoundFiles(self): pass + def setFeatures(self, featureList): + pass + def showMessage(self, message, noTimestamp=False): message = message.encode(sys.stdout.encoding, 'replace') if noTimestamp: @@ -143,6 +146,9 @@ class ConsoleUI(threading.Thread): self._syncplayClient.playerPositionBeforeLastSeek = tmp_pos elif command.group('command') in constants.COMMANDS_LIST: 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: self._syncplayClient.setPaused(not self._syncplayClient.getPlayerPaused()) 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/create"), 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("more-info-notification").format(syncplay.projectURL), True) diff --git a/syncplay/ui/gui.py b/syncplay/ui/gui.py index 27b08d6..a7523d3 100644 --- a/syncplay/ui/gui.py +++ b/syncplay/ui/gui.py @@ -327,11 +327,23 @@ class MainWindow(QtGui.QMainWindow): # TODO: Prompt user 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): message = unicode(message) message = message.replace(u"&", u"&").replace(u'"', u""").replace(u"<", u"<").replace(">", u">") + message = message.replace(u"<<", u"") + message = message.replace(u">>", u"") message = message.replace(u"<", u"<".format(constants.STYLE_USERNAME)) message = message.replace(u">", u">") + message = message.replace(u";", u"<") + message = message.replace(u"", u">") message = message.replace(u"\n", u"
") if noTimestamp: self.newMessage(u"{}
".format(message)) @@ -1025,6 +1037,11 @@ class MainWindow(QtGui.QMainWindow): self._syncplayClient.playlist.changePlaylist(newPlaylist) self._syncplayClient.fileSwitch.updateInfo() + def sendChatMessage(self): + if self.chatInput.text() <> "": + self._syncplayClient.sendChat(self.chatInput.text()) + self.chatInput.setText("") + def addTopLayout(self, window): window.topSplit = self.topSplitter(Qt.Horizontal, self) @@ -1040,12 +1057,28 @@ class MainWindow(QtGui.QMainWindow): window.outputbox.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) window.outputlabel = QtGui.QLabel(getMessage("notifications-heading-label")) + window.chatInput = QtGui.QLineEdit() + 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.setLineWidth(0) window.outputFrame.setMidLineWidth(0) window.outputLayout.setContentsMargins(0, 0, 0, 0) window.outputLayout.addWidget(window.outputlabel) window.outputLayout.addWidget(window.outputbox) + window.outputLayout.addWidget(window.chatFrame) window.outputFrame.setLayout(window.outputLayout) window.listLayout = QtGui.QVBoxLayout() diff --git a/syncplayServer.py b/syncplayServer.py index b4456d7..347b171 100755 --- a/syncplayServer.py +++ b/syncplayServer.py @@ -19,6 +19,5 @@ from syncplay.server import SyncFactory, ConfigurationGetter if __name__ == '__main__': argsGetter = ConfigurationGetter() args = argsGetter.getConfiguration() - - reactor.listenTCP(int(args.port), SyncFactory(args.password, args.motd_file, args.isolate_rooms, args.salt, args.disable_ready)) + reactor.listenTCP(int(args.port), SyncFactory(args.password, args.motd_file, args.isolate_rooms, args.salt, args.disable_ready,args.disable_chat)) reactor.run()