diff --git a/syncplay/client.py b/syncplay/client.py index 821d08b..0e2c50f 100644 --- a/syncplay/client.py +++ b/syncplay/client.py @@ -416,16 +416,16 @@ class SyncplayClient(object): if promptForAction: self.ui.promptFor(getMessage("enter-to-exit-prompt")) - def createControlledRoom(self): + def createControlledRoom(self, roomName): controlPassword = RoomPasswordGenerator.generate_password() - self.ui.showMessage(u"Attempting to create controlled room suffix with password '{}'...".format(controlPassword)) - self._protocol.requestControlledRoom(controlPassword) + self.ui.showMessage(u"Attempting to create controlled room '{}' with password '{}'...".format(roomName, controlPassword)) + self._protocol.requestControlledRoom(roomName, controlPassword) - def controlledRoomCreated(self, controlPassword, roomName): - self.ui.showMessage(u"Created controlled room suffix '{}' with password '{}'. Please save this information for future reference!".format(roomName, controlPassword)) + def controlledRoomCreated(self, roomName, controlPassword): + self.ui.showMessage(u"Created controlled room '{}' with password '{}'. Please save this information for future reference!".format(roomName, controlPassword)) self.setRoom(roomName) self.sendRoom() - self._protocol.requestControlledRoom(controlPassword) + self._protocol.requestControlledRoom(roomName, controlPassword) self.ui.updateRoomName(roomName) def stripControlPassword(self, controlPassword): @@ -437,7 +437,7 @@ class SyncplayClient(object): def identifyAsController(self, controlPassword): controlPassword = self.stripControlPassword(controlPassword) self.ui.showMessage(u"Identifying as room controller with password '{}'...".format(controlPassword)) - self._protocol.requestControlledRoom(controlPassword) + self._protocol.requestControlledRoom(self.getRoom(), controlPassword) def controllerIdentificationError(self, username, room): self.ui.showErrorMessage(u"<{}> failed to identify as a room controller.".format(username)) diff --git a/syncplay/constants.py b/syncplay/constants.py index c2473ad..9bd0065 100644 --- a/syncplay/constants.py +++ b/syncplay/constants.py @@ -41,6 +41,7 @@ SYNC_ON_PAUSE = True # Client seek to global position - subtitles may disappear #Usually there's no need to adjust these 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_LIST = ["l", "list", "users"] COMMANDS_PAUSE = ["p", "play", "pause"] diff --git a/syncplay/messages.py b/syncplay/messages.py index 77a7d07..187ae16 100755 --- a/syncplay/messages.py +++ b/syncplay/messages.py @@ -53,7 +53,7 @@ en = { "commandlist-notification/pause" : "\tp - toggle pause", "commandlist-notification/seek" : "\t[s][+-]time - seek to the given value of time, if + or - is not specified it's absolute time in seconds or min:sec", "commandlist-notification/help" : "\th - this help", - "commandlist-notification/create" : "\tc - create controlled room using name of current room", + "commandlist-notification/create" : "\tc [name] - create controlled room using name of current room", "commandlist-notification/auth" : "\ta [password] - authenticate as room controller with controller password", "syncplay-version-notification" : "Syncplay version: {}", # syncplay.version "more-info-notification" : "More info available at: {}", # projectURL diff --git a/syncplay/protocols.py b/syncplay/protocols.py index 2fa8cdf..67b6026 100644 --- a/syncplay/protocols.py +++ b/syncplay/protocols.py @@ -126,7 +126,7 @@ class SyncClientProtocol(JSONCommandProtocol): elif command == "newControlledRoom": controlPassword = values['password'] roomName = values['roomName'] - self._client.controlledRoomCreated(controlPassword, roomName) + self._client.controlledRoomCreated(roomName, controlPassword) def sendSet(self, setting): self.sendMessage({"Set": setting}) @@ -217,9 +217,10 @@ class SyncClientProtocol(JSONCommandProtocol): state["ignoringOnTheFly"]["client"] = self.clientIgnoringOnTheFly self.sendMessage({"State": state}) - def requestControlledRoom(self, password): + def requestControlledRoom(self, room, password): self.sendSet({ "controllerAuth": { + "room": room, "password": password } }) @@ -325,7 +326,8 @@ class SyncServerProtocol(JSONCommandProtocol): self._watcher.setFile(set_[1]) elif command == "controllerAuth": password = set_[1]["password"] if set_[1].has_key("password") else None - self._factory.authRoomController(self._watcher, password) + room = set_[1]["room"] if set_[1].has_key("room") else None + self._factory.authRoomController(self._watcher, password, room) def sendSet(self, setting): self.sendMessage({"Set": setting}) diff --git a/syncplay/server.py b/syncplay/server.py index 4b1699a..f586be3 100644 --- a/syncplay/server.py +++ b/syncplay/server.py @@ -109,15 +109,16 @@ class SyncFactory(Factory): def getAllWatchersForUser(self, forUser): return self._roomManager.getAllWatchersForUser(forUser) - def authRoomController(self, watcher, password): + def authRoomController(self, watcher, password, roomBaseName=None): room = watcher.getRoom() + roomName = roomBaseName if roomBaseName else room.getName() try: - success = RoomPasswordProvider.check(room.getName(), password, self._salt) + success = RoomPasswordProvider.check(roomName, password, self._salt) if success: watcher.getRoom().addController(watcher) self._roomManager.broadcast(watcher, lambda w: w.sendControlledRoomAuthStatus(success, watcher.getName(), room._name)) except NotControlledRoom: - newName = RoomPasswordProvider.getControlledRoomName(room.getName(), password, self._salt) + newName = RoomPasswordProvider.getControlledRoomName(roomName, password, self._salt) watcher.sendNewControlledRoom(newName, password) except ValueError: self._roomManager.broadcastRoom(watcher, lambda w: w.sendControlledRoomAuthStatus(False, watcher.getName(), room._name)) @@ -343,8 +344,8 @@ class Watcher(object): def sendSetting(self, user, room, file_, event): self._connector.sendUserSetting(user, room, file_, event) - def sendNewControlledRoom(self, roomName, password): - self._connector.sendNewControlledRoom(roomName, password) + def sendNewControlledRoom(self, roomBaseName, password): + self._connector.sendNewControlledRoom(roomBaseName, password) def sendControlledRoomAuthStatus(self, success, username, room): self._connector.sendControlledRoomAuthStatus(success, username, room) diff --git a/syncplay/ui/consoleUI.py b/syncplay/ui/consoleUI.py index 6af11b6..70acede 100644 --- a/syncplay/ui/consoleUI.py +++ b/syncplay/ui/consoleUI.py @@ -144,7 +144,11 @@ class ConsoleUI(threading.Thread): self._syncplayClient.setRoom(room) self._syncplayClient.sendRoom() elif command.group('command') in constants.COMMANDS_CREATE: - self._syncplayClient.createControlledRoom() + roombasename = command.group('parameter') + if roombasename == None: + roombasename = self._syncplayClient.getRoom() + roombasename = utils.stripRoomName(roombasename) + self._syncplayClient.createControlledRoom(roombasename) elif command.group('command') in constants.COMMANDS_AUTH: controlpassword = command.group('parameter') self._syncplayClient.identifyAsController(controlpassword) diff --git a/syncplay/ui/gui.py b/syncplay/ui/gui.py index 2c1f718..db015a4 100644 --- a/syncplay/ui/gui.py +++ b/syncplay/ui/gui.py @@ -275,7 +275,11 @@ class MainWindow(QtGui.QMainWindow): self._syncplayClient._player.openFile(fileName) def createControlledRoom(self): - self._syncplayClient.createControlledRoom() + controlroom, ok = QtGui.QInputDialog.getText(self, "Create controlled room", + "Enter name of controlled room\r\n(see http://syncplay.pl/guide/ for usage instructions):", QtGui.QLineEdit.Normal, + utils.stripRoomName(self._syncplayClient.getRoom())) + if ok and controlroom != '': + self._syncplayClient.createControlledRoom(controlroom) def identifyAsController(self): tooltip = "Enter controller password for this room\r\n(see http://syncplay.pl/guide/ for usage instructions):" diff --git a/syncplay/utils.py b/syncplay/utils.py index 4a611ea..5d6728f 100644 --- a/syncplay/utils.py +++ b/syncplay/utils.py @@ -141,7 +141,19 @@ def blackholeStdoutForFrozenWindow(): # Relate to file hashing / difference checking: def stripfilename(filename): - return re.sub(constants.FILENAME_STRIP_REGEX, "", filename) + if filename: + return re.sub(constants.FILENAME_STRIP_REGEX, "", filename) + else: + return "" + +def stripRoomName(RoomName): + if RoomName: + try: + return re.sub(constants.ROOM_NAME_STRIP_REGEX, "\g", RoomName) + except IndexError: + return RoomName + else: + return "" def hashFilename(filename): return hashlib.sha256(stripfilename(filename).encode('utf-8')).hexdigest()[:12] @@ -196,6 +208,8 @@ class RoomPasswordProvider(object): if not password or not re.match(RoomPasswordProvider.PASSWORD_REGEX, password): raise ValueError() + if not roomName: + raise NotControlledRoom() match = re.match(RoomPasswordProvider.CONTROLLED_ROOM_REGEX, roomName) if not match: raise NotControlledRoom()