예제 #1
0
    def __init__(self):
        self._config = {
                        "host": None,
                        "port": constants.DEFAULT_PORT,
                        "name": None,
                        "debug": False,
                        "forceGuiPrompt": False,
                        "noGui": False,
                        "noStore": False,
                        "room": "",
                        "password": None,
                        "playerPath": None,
                        "file": None,
                        "playerArgs": [],
                        "playerClass": None,
						"slowOnDesync": True
                        }
        
        #
        #Custom validation in self._validateArguments
        #
        self._required = [
                          "host",
                          "port",
                          "name",
                          "playerPath",
                          "playerClass",
                         ]
        
        self._boolean = [
                         "debug",
                         "forceGuiPrompt",
                         "noGui",
                         "noStore",
                         "slowOnDesync"
                        ]

        self._iniStructure = {
                        "server_data": ["host", "port", "password"],
                        "client_settings": ["name", "room", "playerPath", "slowOnDesync", "forceGuiPrompt"]
                        }

        #
        #Watch out for the method self._overrideConfigWithArgs when you're adding custom multi-word command line arguments
        #
        self._argparser = argparse.ArgumentParser(description=getMessage("en", "argument-description"),
                                         epilog=getMessage("en", "argument-epilog"))
        self._argparser.add_argument('--no-gui', action='store_true', help=getMessage("en", "nogui-argument"))
        self._argparser.add_argument('-a', '--host', metavar='hostname', type=str, help=getMessage("en", "host-argument"))
        self._argparser.add_argument('-n', '--name', metavar='username', type=str, help=getMessage("en", "name-argument"))
        self._argparser.add_argument('-d', '--debug', action='store_true', help=getMessage("en", "debug-argument"))
        self._argparser.add_argument('-g', '--force-gui-prompt', action='store_true', help=getMessage("en", "force-gui-prompt-argument"))
        self._argparser.add_argument('--no-store', action='store_true', help=getMessage("en", "no-store-argument"))
        self._argparser.add_argument('-r', '--room', metavar='room', type=str, nargs='?', help=getMessage("en", "room-argument"))
        self._argparser.add_argument('-p', '--password', metavar='password', type=str, nargs='?', help=getMessage("en", "password-argument"))
        self._argparser.add_argument('--player-path', metavar='path', type=str, help=getMessage("en", "player-path-argument"))
        self._argparser.add_argument('file', metavar='file', type=str, nargs='?', help=getMessage("en", "file-argument"))
        self._argparser.add_argument('_args', metavar='options', type=str, nargs='*', help=getMessage("en", "args-argument"))
  
        self._playerFactory = PlayerFactory()
예제 #2
0
    def _tryToFillPlayerPath(self, playerpath, playerpathlist):
        settings = QSettings("Syncplay", "PlayerList")
        settings.beginGroup("PlayerList")
        savedPlayers = settings.value("PlayerList", [])
        if(not isinstance(savedPlayers, list)):
            savedPlayers = []
        playerpathlist = list(set(os.path.normcase(os.path.normpath(path)) for path in set(playerpathlist + savedPlayers)))
        settings.endGroup()
        foundpath = ""

        if playerpath != None and playerpath != "":
            if not os.path.isfile(playerpath):
                expandedpath = PlayerFactory().getExpandedPlayerPathByPath(playerpath)
                if expandedpath != None and os.path.isfile(expandedpath):
                    playerpath = expandedpath

            if os.path.isfile(playerpath):
                foundpath = playerpath
                self.executablepathCombobox.addItem(foundpath)

        for path in playerpathlist:
            if(os.path.isfile(path) and os.path.normcase(os.path.normpath(path)) != os.path.normcase(os.path.normpath(foundpath))):
                self.executablepathCombobox.addItem(path)
                if foundpath == "":
                    foundpath = path

        if foundpath != "":
            settings.beginGroup("PlayerList")
            playerpathlist.append(os.path.normcase(os.path.normpath(foundpath)))
            settings.setValue("PlayerList",  list(set(os.path.normcase(os.path.normpath(path)) for path in set(playerpathlist))))
            settings.endGroup()
        return(foundpath)
예제 #3
0
 def updateExecutableIcon(self):
     currentplayerpath = unicode(self.executablepathCombobox.currentText())
     iconpath = PlayerFactory().getPlayerIconByPath(currentplayerpath)
     if iconpath != None and iconpath != "":
         self.executableiconImage.load(self.resourcespath + iconpath)
         self.executableiconLabel.setPixmap(QtGui.QPixmap.fromImage(self.executableiconImage))
     else:
         self.executableiconLabel.setPixmap(QtGui.QPixmap.fromImage(QtGui.QImage()))
예제 #4
0
class ConfigurationGetter(object):
    def __init__(self):
        self._config = {
                        "host": None,
                        "port": constants.DEFAULT_PORT,
                        "name": None,
                        "debug": False,
                        "forceGuiPrompt": True,
                        "noGui": False,
                        "noStore": False,
                        "room": "",
                        "password": None,
                        "playerPath": None,
                        "perPlayerArguments": None,
                        "mediaSearchDirectories": None,
                        "file": None,
                        "playerArgs": [],
                        "playerClass": None,
                        "slowdownThreshold": constants.DEFAULT_SLOWDOWN_KICKIN_THRESHOLD,
                        "rewindThreshold": constants.DEFAULT_REWIND_THRESHOLD,
                        "fastforwardThreshold": constants.DEFAULT_FASTFORWARD_THRESHOLD,
                        "rewindOnDesync": True,
                        "slowOnDesync": True,
                        "fastforwardOnDesync": True,
                        "dontSlowDownWithMe": False,
                        "filenamePrivacyMode": constants.PRIVACY_SENDRAW_MODE,
                        "filesizePrivacyMode": constants.PRIVACY_SENDRAW_MODE,
                        "pauseOnLeave": False,
                        "readyAtStart": False,
                        "unpauseAction": constants.UNPAUSE_IFOTHERSREADY_MODE,
                        "autoplayInitialState" : None,
                        "autoplayMinUsers" : -1,
                        "clearGUIData": False,
                        "language" : "",
                        "checkForUpdatesAutomatically" : None,
                        "lastCheckedForUpdates" : "",
                        "resetConfig" : False,
                        "showOSD" : True,
                        "showOSDWarnings" : True,
                        "showSlowdownOSD" : True,
                        "showDifferentRoomOSD" : False,
                        "showSameRoomOSD" : True,
                        "showNonControllerOSD" : False,
                        "showContactInfo" : True,
                        "showDurationNotification" : True
                        }

        self._defaultConfig = self._config.copy()

        #
        # Custom validation in self._validateArguments
        #
        self._required = [
                          "host",
                          "port",
                          "room",
                          "playerPath",
                          "playerClass",
                         ]

        self._boolean = [
                         "debug",
                         "forceGuiPrompt",
                         "noGui",
                         "noStore",
                         "dontSlowDownWithMe",
                         "pauseOnLeave",
                         "readyAtStart",
                         "clearGUIData",
                         "rewindOnDesync",
                         "slowOnDesync",
                         "fastforwardOnDesync",
                         "pauseOnLeave",
                         "clearGUIData",
                         "resetConfig",
                         "showOSD",
                         "showOSDWarnings",
                         "showSlowdownOSD",
                         "showDifferentRoomOSD",
                         "showSameRoomOSD",
                         "showNonControllerOSD",
                         "showDurationNotification"
                        ]
        self._tristate = [
            "checkForUpdatesAutomatically",
            "autoplayInitialState",
        ]

        self._serialised = [
            "perPlayerArguments",
            "mediaSearchDirectories",
        ]

        self._numeric = [
            "slowdownThreshold",
            "rewindThreshold",
            "fastforwardThreshold",
            "autoplayMinUsers",
        ]

        self._iniStructure = {
                        "server_data": ["host", "port", "password"],
                        "client_settings": ["name", "room", "playerPath", "perPlayerArguments", "slowdownThreshold", "rewindThreshold", "fastforwardThreshold", "slowOnDesync", "rewindOnDesync", "fastforwardOnDesync", "dontSlowDownWithMe", "forceGuiPrompt", "filenamePrivacyMode", "filesizePrivacyMode", "unpauseAction", "pauseOnLeave", "readyAtStart", "autoplayMinUsers", "autoplayInitialState", "mediaSearchDirectories"],
                        "gui": ["showOSD", "showOSDWarnings", "showSlowdownOSD", "showDifferentRoomOSD", "showSameRoomOSD", "showNonControllerOSD", "showDurationNotification"],
                        "general": ["language", "checkForUpdatesAutomatically", "lastCheckedForUpdates"]
                        }

        self._playerFactory = PlayerFactory()

    def _validateArguments(self):
        if self._config['resetConfig']:
            language = self._config['language']
            checkForUpdatesAutomatically = self._config['checkForUpdatesAutomatically']
            self._config = self._defaultConfig
            self._config['language'] = language
            self._config['checkForUpdatesAutomatically'] = checkForUpdatesAutomatically
            raise InvalidConfigValue("*"+getMessage("config-cleared-notification"))

        if not isValidLanguage(self._config['language']):
            self._config['language'] = ""

        def _isPortValid(varToTest):
            try:
                if varToTest == "" or varToTest is None:
                    return False
                if str(varToTest).isdigit() == False:
                    return False
                varToTest = int(varToTest)
                if varToTest > 65535 or varToTest < 1:
                    return False
                return True
            except:
                return False
        for key in self._boolean:
            if self._config[key] == "True":
                self._config[key] = True
            elif self._config[key] == "False":
                self._config[key] = False

        for key in self._serialised:
            if self._config[key] is None or self._config[key] == "":
                self._config[key] = {}
            elif isinstance(self._config[key], (str, unicode)):
                self._config[key] = ast.literal_eval(self._config[key])

        for key in self._tristate:
            if self._config[key] == "True":
                self._config[key] = True
            elif self._config[key] == "False":
                self._config[key] = False
            elif self._config[key] == "None":
                self._config[key] = None

        for key in self._numeric:
            self._config[key] = float(self._config[key])

        for key in self._required:
            if key == "playerPath":
                player = None
                if self._config["playerPath"]:
                    player = self._playerFactory.getPlayerByPath(self._config["playerPath"])
                if player:
                    self._config["playerClass"] = player
                else:
                    raise InvalidConfigValue(getMessage("player-path-config-error"))
                playerPathErrors = player.getPlayerPathErrors(self._config["playerPath"], self._config['file'] if self._config['file'] else None)
                if playerPathErrors:
                    raise InvalidConfigValue(playerPathErrors)
            elif key == "host":
                self._config["host"], self._config["port"] = self._splitPortAndHost(self._config["host"])
                hostNotValid = (self._config["host"] == "" or self._config["host"] is None)
                portNotValid = (_isPortValid(self._config["port"]) == False)
                if hostNotValid:
                    raise InvalidConfigValue(getMessage("no-hostname-config-error"))
                elif portNotValid:
                    raise InvalidConfigValue(getMessage("invalid-port-config-error"))
            elif self._config[key] == "" or self._config[key] is None:
                raise InvalidConfigValue(getMessage("empty-value-config-error").format(key.capitalize()))

    def _overrideConfigWithArgs(self, args):
        for key, val in vars(args).items():
            if val:
                if key == "force_gui_prompt":
                    key = "forceGuiPrompt"
                if key == "no_store":
                    key = "noStore"
                if key == "player_path":
                    key = "playerPath"
                if key == "_args":
                    key = "playerArgs"
                if key == "no_gui":
                    key = "noGui"
                if key == "clear_gui_data":
                    key = "clearGUIData"
                self._config[key] = val

    def _splitPortAndHost(self, host):
        port = constants.DEFAULT_PORT if not self._config["port"] else self._config["port"]
        if host:
            if ':' in host:
                host, port = host.split(':', 1)
                try:
                    port = int(port)
                except ValueError:
                    try:
                        port = port.encode('ascii', 'ignore')
                    except:
                        port = ""
        return host, port

    def _checkForPortableFile(self):
        path = utils.findWorkingDir()
        for name in constants.CONFIG_NAMES:
            if os.path.isfile(os.path.join(path, name)):
                return os.path.join(path, name)

    def _getConfigurationFilePath(self):
        configFile = self._checkForPortableFile()
        if not configFile:
            for name in constants.CONFIG_NAMES:
                if configFile and os.path.isfile(configFile):
                    break
                if os.name <> 'nt':
                    configFile = os.path.join(os.getenv('HOME', '.'), name)
                else:
                    configFile = os.path.join(os.getenv('APPDATA', '.'), name)
            if configFile and not os.path.isfile(configFile):
                if os.name <> 'nt':
                    configFile = os.path.join(os.getenv('HOME', '.'), constants.DEFAULT_CONFIG_NAME_LINUX)
                else:
                    configFile = os.path.join(os.getenv('APPDATA', '.'), constants.DEFAULT_CONFIG_NAME_WINDOWS)

        return configFile

    def _parseConfigFile(self, iniPath, createConfig=True):
        parser = SafeConfigParserUnicode()
        if not os.path.isfile(iniPath):
            if createConfig:
                open(iniPath, 'w').close()
            else:
                return
        parser.readfp(codecs.open(iniPath, "r", "utf_8_sig"))
        for section, options in self._iniStructure.items():
            if parser.has_section(section):
                for option in options:
                    if parser.has_option(section, option):
                        self._config[option] = parser.get(section, option)

    def _checkConfig(self):
        try:
            self._validateArguments()
        except InvalidConfigValue as e:
            try:
                for key, value in self._promptForMissingArguments(e.message).items():
                    self._config[key] = value
                self._checkConfig()
            except:
                sys.exit()

    def _promptForMissingArguments(self, error=None):
        if self._config['noGui'] or not GuiConfiguration:
            if error:
                print "{}!".format(error)
            print getMessage("missing-arguments-error")
            sys.exit()
        elif GuiConfiguration:
            gc = GuiConfiguration(self._config, error=error)
            gc.setAvailablePaths(self._playerFactory.getAvailablePlayerPaths())
            gc.run()
            return gc.getProcessedConfiguration()

    def __wasOptionChanged(self, parser, section, option):
        if parser.has_option(section, option):
            if parser.get(section, option) != unicode(self._config[option]):
                return True
        else:
            return True

    def _saveConfig(self, iniPath):
        changed = False
        if self._config['noStore']:
            return
        parser = SafeConfigParserUnicode()
        parser.readfp(codecs.open(iniPath, "r", "utf_8_sig"))
        for section, options in self._iniStructure.items():
            if not parser.has_section(section):
                parser.add_section(section)
                changed = True
            for option in options:
                if self.__wasOptionChanged(parser, section, option):
                    changed = True
                parser.set(section, option, unicode(self._config[option]).replace('%', '%%'))
        if changed:
            parser.write(codecs.open(iniPath, "wb", "utf_8_sig"))


    def _forceGuiPrompt(self):
        if GuiConfiguration:
            try:
                self._validateArguments()
            except InvalidConfigValue:
                pass

            try:
                if self._config['noGui'] == False:
                    for key, value in self._promptForMissingArguments().items():
                        self._config[key] = value
            except GuiConfiguration.WindowClosed:
                sys.exit()
        else:
            try:
                self._validateArguments()
            except InvalidConfigValue:
                self._promptForMissingArguments()
                sys.exit()

    def __getRelativeConfigLocations(self):
        locations = []
        path = os.path.dirname(os.path.realpath(self._config['file']))
        locations.append(path)
        while path != os.path.dirname(path):
            path = os.path.dirname(path)
            locations.append(path)
        locations.reverse()
        return locations

    def _loadRelativeConfiguration(self):
        locations = self.__getRelativeConfigLocations()
        loadedPaths = []
        for location in locations:
            for name in constants.CONFIG_NAMES:
                path = location + os.path.sep + name
                if os.path.isfile(path) and (os.name == 'nt' or path != os.path.join(os.getenv('HOME', '.'), constants.DEFAULT_CONFIG_NAME_LINUX)):
                    loadedPaths.append("'" + os.path.normpath(path) + "'")
                    self._parseConfigFile(path, createConfig=False)
                    self._checkConfig()
        return loadedPaths

    def getConfiguration(self):
        iniPath = self._getConfigurationFilePath()
        self._parseConfigFile(iniPath)
        #
        # Watch out for the method self._overrideConfigWithArgs when you're adding custom multi-word command line arguments
        #
        if self._config['language']:
            setLanguage(self._config['language'])
        self._argparser = argparse.ArgumentParser(description=getMessage("argument-description"),
                                         epilog=getMessage("argument-epilog"))
        self._argparser.add_argument('--no-gui', action='store_true', help=getMessage("nogui-argument"))
        self._argparser.add_argument('-a', '--host', metavar='hostname', type=str, help=getMessage("host-argument"))
        self._argparser.add_argument('-n', '--name', metavar='username', type=str, help=getMessage("name-argument"))
        self._argparser.add_argument('-d', '--debug', action='store_true', help=getMessage("debug-argument"))
        self._argparser.add_argument('-g', '--force-gui-prompt', action='store_true', help=getMessage("force-gui-prompt-argument"))
        self._argparser.add_argument('--no-store', action='store_true', help=getMessage("no-store-argument"))
        self._argparser.add_argument('-r', '--room', metavar='room', type=str, nargs='?', help=getMessage("room-argument"))
        self._argparser.add_argument('-p', '--password', metavar='password', type=str, nargs='?', help=getMessage("password-argument"))
        self._argparser.add_argument('--player-path', metavar='path', type=str, help=getMessage("player-path-argument"))
        self._argparser.add_argument('--language', metavar='language', type=str, help=getMessage("language-argument"))
        self._argparser.add_argument('file', metavar='file', type=str, nargs='?', help=getMessage("file-argument"))
        self._argparser.add_argument('--clear-gui-data', action='store_true', help=getMessage("clear-gui-data-argument"))
        self._argparser.add_argument('-v', '--version', action='store_true', help=getMessage("version-argument"))
        self._argparser.add_argument('_args', metavar='options', type=str, nargs='*', help=getMessage("args-argument"))
        args = self._argparser.parse_args()
        if args.version:
            print getMessage("version-message").format(version, milestone)
            sys.exit()
        self._overrideConfigWithArgs(args)
        if self._config['file'] and self._config['file'][:2] == "--":
            self._config['playerArgs'].insert(0, self._config['file'])
            self._config['file'] = None
        # Arguments not validated yet - booleans are still text values
        if self._config['language']:
            setLanguage(self._config['language'])
        if (self._config['forceGuiPrompt'] == "True" or not self._config['file']) and GuiConfiguration and not self._config['noGui']:
            self._forceGuiPrompt()
        self._checkConfig()
        self._saveConfig(iniPath)
        if self._config['file']:
            self._config['loadedRelativePaths'] = self._loadRelativeConfiguration()
        if self._config['language']:
            setLanguage(self._config['language'])
        if not GuiConfiguration:
            self._config['noGui'] = True
        if not self._config['noGui']:
            from syncplay.vendor import qt4reactor
            if QCoreApplication.instance() is None:
                self.app = QtGui.QApplication(sys.argv)
            qt4reactor.install()
        return self._config
예제 #5
0
    def __init__(self):
        self._config = {
            "host": None,
            "port": constants.DEFAULT_PORT,
            "name": None,
            "debug": False,
            "forceGuiPrompt": True,
            "noGui": False,
            "noStore": False,
            "room": "",
            "password": None,
            "playerPath": None,
            "perPlayerArguments": None,
            "mediaSearchDirectories": None,
            "sharedPlaylistEnabled": True,
            "loopAtEndOfPlaylist": False,
            "loopSingleFiles": False,
            "onlySwitchToTrustedDomains": True,
            "trustedDomains": constants.DEFAULT_TRUSTED_DOMAINS,
            "file": None,
            "playerArgs": [],
            "playerClass": None,
            "slowdownThreshold": constants.DEFAULT_SLOWDOWN_KICKIN_THRESHOLD,
            "rewindThreshold": constants.DEFAULT_REWIND_THRESHOLD,
            "fastforwardThreshold": constants.DEFAULT_FASTFORWARD_THRESHOLD,
            "rewindOnDesync": True,
            "slowOnDesync": True,
            "fastforwardOnDesync": True,
            "dontSlowDownWithMe": False,
            "filenamePrivacyMode": constants.PRIVACY_SENDRAW_MODE,
            "filesizePrivacyMode": constants.PRIVACY_SENDRAW_MODE,
            "pauseOnLeave": False,
            "readyAtStart": False,
            "unpauseAction": constants.UNPAUSE_IFOTHERSREADY_MODE,
            "autoplayInitialState": None,
            "autoplayMinUsers": -1,
            "autoplayRequireSameFilenames": True,
            "clearGUIData": False,
            "language": "",
            "checkForUpdatesAutomatically": None,
            "lastCheckedForUpdates": "",
            "resetConfig": False,
            "showOSD": True,
            "showOSDWarnings": True,
            "showSlowdownOSD": True,
            "showDifferentRoomOSD": False,
            "showSameRoomOSD": True,
            "showNonControllerOSD": False,
            "showContactInfo": True,
            "showDurationNotification": True,
            "chatInputEnabled": True,
            "chatInputFontFamily": 'sans-serif',
            "chatInputRelativeFontSize": constants.DEFAULT_CHAT_FONT_SIZE,
            "chatInputFontWeight": constants.DEFAULT_CHAT_FONT_WEIGHT,
            "chatInputFontUnderline": False,
            "chatInputFontColor": constants.DEFAULT_CHAT_INPUT_FONT_COLOR,
            "chatInputPosition": constants.INPUT_POSITION_TOP,
            "chatDirectInput": False,
            "chatOutputEnabled": True,
            "chatOutputFontFamily": 'sans-serif',
            "chatOutputRelativeFontSize": constants.DEFAULT_CHAT_FONT_SIZE,
            "chatOutputFontWeight": constants.DEFAULT_CHAT_FONT_WEIGHT,
            "chatOutputFontUnderline": False,
            "chatOutputMode": constants.CHATROOM_MODE,
            "chatMaxLines": 7,
            "chatTopMargin": 25,
            "chatLeftMargin": 20,
            "chatBottomMargin": 30,
            "chatMoveOSD": True,
            "chatOSDMargin": 110,
            "notificationTimeout": 3,
            "alertTimeout": 5,
            "chatTimeout": 7,
            "publicServers": []
        }

        self._defaultConfig = self._config.copy()

        #
        # Custom validation in self._validateArguments
        #
        self._required = [
            "host",
            "port",
            "room",
            "playerPath",
            "playerClass",
        ]

        self._boolean = [
            "debug", "forceGuiPrompt", "noGui", "noStore",
            "dontSlowDownWithMe", "pauseOnLeave", "readyAtStart",
            "autoplayRequireSameFilenames", "clearGUIData", "rewindOnDesync",
            "slowOnDesync", "fastforwardOnDesync", "pauseOnLeave",
            "clearGUIData", "resetConfig", "showOSD", "showOSDWarnings",
            "showSlowdownOSD", "showDifferentRoomOSD", "showSameRoomOSD",
            "showNonControllerOSD", "showDurationNotification",
            "sharedPlaylistEnabled", "loopAtEndOfPlaylist", "loopSingleFiles",
            "onlySwitchToTrustedDomains", "chatInputEnabled",
            "chatInputFontUnderline", "chatDirectInput", "chatMoveOSD",
            "chatOutputEnabled", "chatOutputFontUnderline"
        ]
        self._tristate = [
            "checkForUpdatesAutomatically",
            "autoplayInitialState",
        ]

        self._serialised = [
            "perPlayerArguments",
            "mediaSearchDirectories",
            "trustedDomains",
            "publicServers",
        ]

        self._numeric = [
            "slowdownThreshold", "rewindThreshold", "fastforwardThreshold",
            "autoplayMinUsers", "chatInputRelativeFontSize",
            "chatInputFontWeight", "chatOutputFontWeight",
            "chatOutputRelativeFontSize", "chatMaxLines", "chatTopMargin",
            "chatLeftMargin", "chatBottomMargin", "chatOSDMargin",
            "notificationTimeout", "alertTimeout", "chatTimeout"
        ]

        self._hexadecimal = ["chatInputFontColor"]

        self._iniStructure = {
            "server_data": ["host", "port", "password"],
            "client_settings": [
                "name", "room", "playerPath", "perPlayerArguments",
                "slowdownThreshold", "rewindThreshold", "fastforwardThreshold",
                "slowOnDesync", "rewindOnDesync", "fastforwardOnDesync",
                "dontSlowDownWithMe", "forceGuiPrompt", "filenamePrivacyMode",
                "filesizePrivacyMode", "unpauseAction", "pauseOnLeave",
                "readyAtStart", "autoplayMinUsers", "autoplayInitialState",
                "mediaSearchDirectories", "sharedPlaylistEnabled",
                "loopAtEndOfPlaylist", "loopSingleFiles",
                "onlySwitchToTrustedDomains", "trustedDomains", "publicServers"
            ],
            "gui": [
                "showOSD", "showOSDWarnings", "showSlowdownOSD",
                "showDifferentRoomOSD", "showSameRoomOSD",
                "showNonControllerOSD", "showDurationNotification",
                "chatInputEnabled", "chatInputFontUnderline",
                "chatInputFontFamily", "chatInputRelativeFontSize",
                "chatInputFontWeight", "chatInputFontColor",
                "chatInputPosition", "chatDirectInput", "chatOutputFontFamily",
                "chatOutputRelativeFontSize", "chatOutputFontWeight",
                "chatOutputFontUnderline", "chatOutputMode", "chatMaxLines",
                "chatTopMargin", "chatLeftMargin", "chatBottomMargin",
                "chatDirectInput", "chatMoveOSD", "chatOSDMargin",
                "notificationTimeout", "alertTimeout", "chatTimeout",
                "chatOutputEnabled"
            ],
            "general": [
                "language", "checkForUpdatesAutomatically",
                "lastCheckedForUpdates"
            ]
        }

        self._playerFactory = PlayerFactory()
예제 #6
0
class ConfigurationGetter(object):
    def __init__(self):
        self._config = {
            "host": None,
            "port": constants.DEFAULT_PORT,
            "name": None,
            "debug": False,
            "forceGuiPrompt": True,
            "noGui": False,
            "noStore": False,
            "room": "",
            "password": None,
            "playerPath": None,
            "perPlayerArguments": None,
            "mediaSearchDirectories": None,
            "sharedPlaylistEnabled": True,
            "loopAtEndOfPlaylist": False,
            "loopSingleFiles": False,
            "onlySwitchToTrustedDomains": True,
            "trustedDomains": constants.DEFAULT_TRUSTED_DOMAINS,
            "file": None,
            "playerArgs": [],
            "playerClass": None,
            "slowdownThreshold": constants.DEFAULT_SLOWDOWN_KICKIN_THRESHOLD,
            "rewindThreshold": constants.DEFAULT_REWIND_THRESHOLD,
            "fastforwardThreshold": constants.DEFAULT_FASTFORWARD_THRESHOLD,
            "rewindOnDesync": True,
            "slowOnDesync": True,
            "fastforwardOnDesync": True,
            "dontSlowDownWithMe": False,
            "filenamePrivacyMode": constants.PRIVACY_SENDRAW_MODE,
            "filesizePrivacyMode": constants.PRIVACY_SENDRAW_MODE,
            "pauseOnLeave": False,
            "readyAtStart": False,
            "unpauseAction": constants.UNPAUSE_IFOTHERSREADY_MODE,
            "autoplayInitialState": None,
            "autoplayMinUsers": -1,
            "autoplayRequireSameFilenames": True,
            "clearGUIData": False,
            "language": "",
            "checkForUpdatesAutomatically": None,
            "lastCheckedForUpdates": "",
            "resetConfig": False,
            "showOSD": True,
            "showOSDWarnings": True,
            "showSlowdownOSD": True,
            "showDifferentRoomOSD": False,
            "showSameRoomOSD": True,
            "showNonControllerOSD": False,
            "showContactInfo": True,
            "showDurationNotification": True,
            "chatInputEnabled": True,
            "chatInputFontFamily": 'sans-serif',
            "chatInputRelativeFontSize": constants.DEFAULT_CHAT_FONT_SIZE,
            "chatInputFontWeight": constants.DEFAULT_CHAT_FONT_WEIGHT,
            "chatInputFontUnderline": False,
            "chatInputFontColor": constants.DEFAULT_CHAT_INPUT_FONT_COLOR,
            "chatInputPosition": constants.INPUT_POSITION_TOP,
            "chatDirectInput": False,
            "chatOutputEnabled": True,
            "chatOutputFontFamily": 'sans-serif',
            "chatOutputRelativeFontSize": constants.DEFAULT_CHAT_FONT_SIZE,
            "chatOutputFontWeight": constants.DEFAULT_CHAT_FONT_WEIGHT,
            "chatOutputFontUnderline": False,
            "chatOutputMode": constants.CHATROOM_MODE,
            "chatMaxLines": 7,
            "chatTopMargin": 25,
            "chatLeftMargin": 20,
            "chatBottomMargin": 30,
            "chatMoveOSD": True,
            "chatOSDMargin": 110,
            "notificationTimeout": 3,
            "alertTimeout": 5,
            "chatTimeout": 7,
            "publicServers": []
        }

        self._defaultConfig = self._config.copy()

        #
        # Custom validation in self._validateArguments
        #
        self._required = [
            "host",
            "port",
            "room",
            "playerPath",
            "playerClass",
        ]

        self._boolean = [
            "debug", "forceGuiPrompt", "noGui", "noStore",
            "dontSlowDownWithMe", "pauseOnLeave", "readyAtStart",
            "autoplayRequireSameFilenames", "clearGUIData", "rewindOnDesync",
            "slowOnDesync", "fastforwardOnDesync", "pauseOnLeave",
            "clearGUIData", "resetConfig", "showOSD", "showOSDWarnings",
            "showSlowdownOSD", "showDifferentRoomOSD", "showSameRoomOSD",
            "showNonControllerOSD", "showDurationNotification",
            "sharedPlaylistEnabled", "loopAtEndOfPlaylist", "loopSingleFiles",
            "onlySwitchToTrustedDomains", "chatInputEnabled",
            "chatInputFontUnderline", "chatDirectInput", "chatMoveOSD",
            "chatOutputEnabled", "chatOutputFontUnderline"
        ]
        self._tristate = [
            "checkForUpdatesAutomatically",
            "autoplayInitialState",
        ]

        self._serialised = [
            "perPlayerArguments",
            "mediaSearchDirectories",
            "trustedDomains",
            "publicServers",
        ]

        self._numeric = [
            "slowdownThreshold", "rewindThreshold", "fastforwardThreshold",
            "autoplayMinUsers", "chatInputRelativeFontSize",
            "chatInputFontWeight", "chatOutputFontWeight",
            "chatOutputRelativeFontSize", "chatMaxLines", "chatTopMargin",
            "chatLeftMargin", "chatBottomMargin", "chatOSDMargin",
            "notificationTimeout", "alertTimeout", "chatTimeout"
        ]

        self._hexadecimal = ["chatInputFontColor"]

        self._iniStructure = {
            "server_data": ["host", "port", "password"],
            "client_settings": [
                "name", "room", "playerPath", "perPlayerArguments",
                "slowdownThreshold", "rewindThreshold", "fastforwardThreshold",
                "slowOnDesync", "rewindOnDesync", "fastforwardOnDesync",
                "dontSlowDownWithMe", "forceGuiPrompt", "filenamePrivacyMode",
                "filesizePrivacyMode", "unpauseAction", "pauseOnLeave",
                "readyAtStart", "autoplayMinUsers", "autoplayInitialState",
                "mediaSearchDirectories", "sharedPlaylistEnabled",
                "loopAtEndOfPlaylist", "loopSingleFiles",
                "onlySwitchToTrustedDomains", "trustedDomains", "publicServers"
            ],
            "gui": [
                "showOSD", "showOSDWarnings", "showSlowdownOSD",
                "showDifferentRoomOSD", "showSameRoomOSD",
                "showNonControllerOSD", "showDurationNotification",
                "chatInputEnabled", "chatInputFontUnderline",
                "chatInputFontFamily", "chatInputRelativeFontSize",
                "chatInputFontWeight", "chatInputFontColor",
                "chatInputPosition", "chatDirectInput", "chatOutputFontFamily",
                "chatOutputRelativeFontSize", "chatOutputFontWeight",
                "chatOutputFontUnderline", "chatOutputMode", "chatMaxLines",
                "chatTopMargin", "chatLeftMargin", "chatBottomMargin",
                "chatDirectInput", "chatMoveOSD", "chatOSDMargin",
                "notificationTimeout", "alertTimeout", "chatTimeout",
                "chatOutputEnabled"
            ],
            "general": [
                "language", "checkForUpdatesAutomatically",
                "lastCheckedForUpdates"
            ]
        }

        self._playerFactory = PlayerFactory()

    def _validateArguments(self):
        if self._config['resetConfig']:
            language = self._config['language']
            checkForUpdatesAutomatically = self._config[
                'checkForUpdatesAutomatically']
            self._config = self._defaultConfig
            self._config['language'] = language
            self._config[
                'checkForUpdatesAutomatically'] = checkForUpdatesAutomatically
            raise InvalidConfigValue("*" +
                                     getMessage("config-cleared-notification"))

        if not isValidLanguage(self._config['language']):
            self._config['language'] = ""

        def _isPortValid(varToTest):
            try:
                if varToTest == "" or varToTest is None:
                    return False
                if not str(varToTest).isdigit():
                    return False
                varToTest = int(varToTest)
                if varToTest > 65535 or varToTest < 1:
                    return False
                return True
            except:
                return False

        for key in self._boolean:
            if self._config[key] == "True":
                self._config[key] = True
            elif self._config[key] == "False":
                self._config[key] = False

        for key in self._serialised:
            if self._config[key] is None or self._config[key] == "":
                self._config[key] = {}
            elif isinstance(self._config[key], str):
                self._config[key] = ast.literal_eval(self._config[key])

        for key in self._tristate:
            if self._config[key] == "True":
                self._config[key] = True
            elif self._config[key] == "False":
                self._config[key] = False
            elif self._config[key] == "None":
                self._config[key] = None

        for key in self._numeric:
            self._config[key] = float(self._config[key])

        for key in self._hexadecimal:
            match = re.search(r'^#(?:[0-9a-fA-F]){6}$', self._config[key])
            if not match:
                self._config[key] = "#FFFFFF"

        for key in self._required:
            if key == "playerPath":
                player = None
                if self._config["playerPath"]:
                    player = self._playerFactory.getPlayerByPath(
                        self._config["playerPath"])
                if player:
                    self._config["playerClass"] = player
                else:
                    raise InvalidConfigValue(
                        getMessage("player-path-config-error"))
                playerPathErrors = player.getPlayerPathErrors(
                    self._config["playerPath"],
                    self._config['file'] if self._config['file'] else None)
                if playerPathErrors:
                    raise InvalidConfigValue(playerPathErrors)
            elif key == "host":
                self._config["host"], self._config[
                    "port"] = self._splitPortAndHost(self._config["host"])
                hostNotValid = (self._config["host"] == ""
                                or self._config["host"] is None)
                portNotValid = (_isPortValid(self._config["port"]) == False)
                if hostNotValid:
                    raise InvalidConfigValue(
                        getMessage("no-hostname-config-error"))
                elif portNotValid:
                    raise InvalidConfigValue(
                        getMessage("invalid-port-config-error"))
            elif self._config[key] == "" or self._config[key] is None:
                raise InvalidConfigValue(
                    getMessage("empty-value-config-error").format(
                        key.capitalize()))

    def _overrideConfigWithArgs(self, args):
        for key, val in list(vars(args).items()):
            if val:
                if key == "force_gui_prompt":
                    key = "forceGuiPrompt"
                if key == "no_store":
                    key = "noStore"
                if key == "player_path":
                    key = "playerPath"
                if key == "_args":
                    key = "playerArgs"
                if key == "no_gui":
                    key = "noGui"
                if key == "clear_gui_data":
                    key = "clearGUIData"
                self._config[key] = val

    def _splitPortAndHost(self, host):
        port = constants.DEFAULT_PORT if not self._config[
            "port"] else self._config["port"]
        if host:
            if ':' in host:
                host, port = host.split(':', 1)
                try:
                    port = int(port)
                except ValueError:
                    try:
                        port = port.encode('ascii', 'ignore')
                    except:
                        port = ""
        return host, port

    def _checkForPortableFile(self):
        path = utils.findWorkingDir()
        for name in constants.CONFIG_NAMES:
            if os.path.isfile(os.path.join(path, name)):
                return os.path.join(path, name)

    def _getConfigurationFilePath(self):
        configFile = self._checkForPortableFile()
        if configFile:
            return configFile
        for name in constants.CONFIG_NAMES:
            configFile = self._expandConfigPath(name, xdg=False)
            if os.path.isfile(configFile):
                return configFile
        return self._expandConfigPath()

    def _expandConfigPath(self, name=None, xdg=True):
        if os.name != 'nt':
            if xdg:
                prefix = self._getXdgConfigHome()
            else:
                prefix = os.getenv('HOME', '.')
        else:
            prefix = os.getenv('APPDATA', '.')
        return os.path.join(prefix, name or constants.DEFAULT_CONFIG_NAME)

    def _getXdgConfigHome(self):
        path = os.getenv('XDG_CONFIG_HOME', os.path.expanduser('~/.config'))
        if not os.path.isdir(path):
            os.mkdir(path, 0o755)
        return path

    def _parseConfigFile(self, iniPath, createConfig=True):
        parser = SafeConfigParserUnicode(strict=False)
        if not os.path.isfile(iniPath):
            if createConfig:
                open(iniPath, 'w').close()
            else:
                return
        parser.readfp(codecs.open(iniPath, "r", "utf_8_sig"))
        for section, options in list(self._iniStructure.items()):
            if parser.has_section(section):
                for option in options:
                    if parser.has_option(section, option):
                        self._config[option] = parser.get(section, option)

    def _checkConfig(self):
        try:
            self._validateArguments()
        except InvalidConfigValue as e:
            try:
                for key, value in list(
                        self._promptForMissingArguments(e).items()):
                    self._config[key] = value
                self._checkConfig()
            except:
                sys.exit()

    def _promptForMissingArguments(self, error=None):
        if self._config['noGui']:
            if error:
                print("{}!".format(error))
            print(getMessage("missing-arguments-error"))
            sys.exit()
        else:
            from syncplay.ui.GuiConfiguration import GuiConfiguration
            gc = GuiConfiguration(self._config, error=error)
            gc.setAvailablePaths(self._playerFactory.getAvailablePlayerPaths())
            gc.run()
            return gc.getProcessedConfiguration()

    def __wasOptionChanged(self, parser, section, option):
        if parser.has_option(section, option):
            if parser.get(section, option) != str(self._config[option]):
                return True
        else:
            return True

    def _saveConfig(self, iniPath):
        changed = False
        if self._config['noStore']:
            return
        parser = SafeConfigParserUnicode(strict=False)
        parser.readfp(codecs.open(iniPath, "r", "utf_8_sig"))
        for section, options in list(self._iniStructure.items()):
            if not parser.has_section(section):
                parser.add_section(section)
                changed = True
            for option in options:
                if self.__wasOptionChanged(parser, section, option):
                    changed = True
                parser.set(section, option,
                           str(self._config[option]).replace('%', '%%'))
        if changed:
            parser.write(codecs.open(iniPath, "wb", "utf_8_sig"))

    def _forceGuiPrompt(self):
        from syncplay.ui.GuiConfiguration import GuiConfiguration
        try:
            self._validateArguments()
        except InvalidConfigValue:
            pass

        try:
            for key, value in list(self._promptForMissingArguments().items()):
                self._config[key] = value
        except GuiConfiguration.WindowClosed:
            sys.exit()

    def __getRelativeConfigLocations(self):
        locations = []
        path = os.path.dirname(os.path.realpath(self._config['file']))
        locations.append(path)
        while path != os.path.dirname(path):
            path = os.path.dirname(path)
            locations.append(path)
        locations.reverse()
        return locations

    def _loadRelativeConfiguration(self):
        locations = self.__getRelativeConfigLocations()
        loadedPaths = []
        for location in locations:
            for name in constants.CONFIG_NAMES:
                path = location + os.path.sep + name
                if os.path.isfile(path) and (
                        os.name == 'nt'
                        or path != os.path.join(os.getenv('HOME', '.'), name)):
                    loadedPaths.append("'{}'".format(os.path.normpath(path)))
                    self._parseConfigFile(path, createConfig=False)
                    self._checkConfig()
        return loadedPaths

    def getConfiguration(self):
        iniPath = self._getConfigurationFilePath()
        self._parseConfigFile(iniPath)
        #
        # Watch out for the method self._overrideConfigWithArgs when you're adding custom multi-word command line arguments
        #
        if self._config['language']:
            setLanguage(self._config['language'])
        self._argparser = argparse.ArgumentParser(
            description=getMessage("argument-description"),
            epilog=getMessage("argument-epilog"))
        self._argparser.add_argument('--no-gui',
                                     action='store_true',
                                     help=getMessage("nogui-argument"))
        self._argparser.add_argument('-a',
                                     '--host',
                                     metavar='hostname',
                                     type=str,
                                     help=getMessage("host-argument"))
        self._argparser.add_argument('-n',
                                     '--name',
                                     metavar='username',
                                     type=str,
                                     help=getMessage("name-argument"))
        self._argparser.add_argument('-d',
                                     '--debug',
                                     action='store_true',
                                     help=getMessage("debug-argument"))
        self._argparser.add_argument(
            '-g',
            '--force-gui-prompt',
            action='store_true',
            help=getMessage("force-gui-prompt-argument"))
        self._argparser.add_argument('--no-store',
                                     action='store_true',
                                     help=getMessage("no-store-argument"))
        self._argparser.add_argument('-r',
                                     '--room',
                                     metavar='room',
                                     type=str,
                                     nargs='?',
                                     help=getMessage("room-argument"))
        self._argparser.add_argument('-p',
                                     '--password',
                                     metavar='password',
                                     type=str,
                                     nargs='?',
                                     help=getMessage("password-argument"))
        self._argparser.add_argument('--player-path',
                                     metavar='path',
                                     type=str,
                                     help=getMessage("player-path-argument"))
        self._argparser.add_argument('--language',
                                     metavar='language',
                                     type=str,
                                     help=getMessage("language-argument"))
        self._argparser.add_argument('file',
                                     metavar='file',
                                     type=str,
                                     nargs='?',
                                     help=getMessage("file-argument"))
        self._argparser.add_argument(
            '--clear-gui-data',
            action='store_true',
            help=getMessage("clear-gui-data-argument"))
        self._argparser.add_argument('-v',
                                     '--version',
                                     action='store_true',
                                     help=getMessage("version-argument"))
        self._argparser.add_argument('_args',
                                     metavar='options',
                                     type=str,
                                     nargs='*',
                                     help=getMessage("args-argument"))
        args = self._argparser.parse_args()
        if args.version:
            print(getMessage("version-message").format(version, milestone))
            sys.exit()
        self._overrideConfigWithArgs(args)
        if not self._config['noGui']:
            try:
                from syncplay.vendor.Qt import QtWidgets, IsPySide, IsPySide2
                from syncplay.vendor.Qt.QtCore import QCoreApplication
                from syncplay.vendor import qt5reactor
                if not (IsPySide2 or IsPySide):
                    raise ImportError
                if QCoreApplication.instance() is None:
                    self.app = QtWidgets.QApplication(sys.argv)
                qt5reactor.install()
                if isMacOS():
                    import appnope
                    appnope.nope()
            except ImportError:
                try:
                    from twisted.trial import unittest
                except:
                    print(getMessage("unable-import-twisted-error"))
                    sys.exit()
                print(getMessage("unable-import-gui-error"))
                self._config['noGui'] = True
        if self._config['file'] and self._config['file'][:2] == "--":
            self._config['playerArgs'].insert(0, self._config['file'])
            self._config['file'] = None
        # Arguments not validated yet - booleans are still text values
        if self._config['language']:
            setLanguage(self._config['language'])
        if (self._config['forceGuiPrompt'] == "True"
                or not self._config['file']) and not self._config['noGui']:
            self._forceGuiPrompt()
        self._checkConfig()
        self._saveConfig(iniPath)
        if self._config['file']:
            self._config[
                'loadedRelativePaths'] = self._loadRelativeConfiguration()
        if self._config['language']:
            setLanguage(self._config['language'])
        return self._config

    def setConfigOption(self, option, value):
        path = self._getConfigurationFilePath()
        backup = self._config.copy()
        self._parseConfigFile(path)
        self._config[option] = value
        backup[option] = value
        self._saveConfig(path)
        self._config = backup
예제 #7
0
    def __init__(self):
        self._config = {
            "host": None,
            "port": constants.DEFAULT_PORT,
            "name": None,
            "debug": False,
            "forceGuiPrompt": True,
            "noGui": False,
            "noStore": False,
            "room": "",
            "password": None,
            "playerPath": None,
            "perPlayerArguments": None,
            "mediaSearchDirectories": None,
            "sharedPlaylistEnabled": True,
            "loopAtEndOfPlaylist": False,
            "loopSingleFiles": False,
            "onlySwitchToTrustedDomains": True,
            "trustedDomains": constants.DEFAULT_TRUSTED_DOMAINS,
            "file": None,
            "playerArgs": [],
            "playerClass": None,
            "slowdownThreshold": constants.DEFAULT_SLOWDOWN_KICKIN_THRESHOLD,
            "rewindThreshold": constants.DEFAULT_REWIND_THRESHOLD,
            "fastforwardThreshold": constants.DEFAULT_FASTFORWARD_THRESHOLD,
            "rewindOnDesync": True,
            "slowOnDesync": True,
            "fastforwardOnDesync": True,
            "dontSlowDownWithMe": False,
            "filenamePrivacyMode": constants.PRIVACY_SENDRAW_MODE,
            "filesizePrivacyMode": constants.PRIVACY_SENDRAW_MODE,
            "pauseOnLeave": False,
            "readyAtStart": False,
            "unpauseAction": constants.UNPAUSE_IFOTHERSREADY_MODE,
            "autoplayInitialState": None,
            "autoplayMinUsers": -1,
            "autoplayRequireSameFilenames": True,
            "clearGUIData": False,
            "language": "",
            "checkForUpdatesAutomatically": None,
            "lastCheckedForUpdates": "",
            "resetConfig": False,
            "showOSD": True,
            "showOSDWarnings": True,
            "showSlowdownOSD": True,
            "showDifferentRoomOSD": False,
            "showSameRoomOSD": True,
            "showNonControllerOSD": False,
            "showContactInfo": True,
            "showDurationNotification": True
        }

        self._defaultConfig = self._config.copy()

        #
        # Custom validation in self._validateArguments
        #
        self._required = [
            "host",
            "port",
            "room",
            "playerPath",
            "playerClass",
        ]

        self._boolean = [
            "debug", "forceGuiPrompt", "noGui", "noStore",
            "dontSlowDownWithMe", "pauseOnLeave", "readyAtStart",
            "autoplayRequireSameFilenames", "clearGUIData", "rewindOnDesync",
            "slowOnDesync", "fastforwardOnDesync", "pauseOnLeave",
            "clearGUIData", "resetConfig", "showOSD", "showOSDWarnings",
            "showSlowdownOSD", "showDifferentRoomOSD", "showSameRoomOSD",
            "showNonControllerOSD", "showDurationNotification",
            "sharedPlaylistEnabled", "loopAtEndOfPlaylist", "loopSingleFiles",
            "onlySwitchToTrustedDomains"
        ]
        self._tristate = [
            "checkForUpdatesAutomatically",
            "autoplayInitialState",
        ]

        self._serialised = [
            "perPlayerArguments",
            "mediaSearchDirectories",
            "trustedDomains",
        ]

        self._numeric = [
            "slowdownThreshold",
            "rewindThreshold",
            "fastforwardThreshold",
            "autoplayMinUsers",
        ]

        self._iniStructure = {
            "server_data": ["host", "port", "password"],
            "client_settings": [
                "name", "room", "playerPath", "perPlayerArguments",
                "slowdownThreshold", "rewindThreshold", "fastforwardThreshold",
                "slowOnDesync", "rewindOnDesync", "fastforwardOnDesync",
                "dontSlowDownWithMe", "forceGuiPrompt", "filenamePrivacyMode",
                "filesizePrivacyMode", "unpauseAction", "pauseOnLeave",
                "readyAtStart", "autoplayMinUsers", "autoplayInitialState",
                "mediaSearchDirectories", "sharedPlaylistEnabled",
                "loopAtEndOfPlaylist", "loopSingleFiles",
                "onlySwitchToTrustedDomains", "trustedDomains"
            ],
            "gui": [
                "showOSD", "showOSDWarnings", "showSlowdownOSD",
                "showDifferentRoomOSD", "showSameRoomOSD",
                "showNonControllerOSD", "showDurationNotification"
            ],
            "general": [
                "language", "checkForUpdatesAutomatically",
                "lastCheckedForUpdates"
            ]
        }

        self._playerFactory = PlayerFactory()
예제 #8
0
    def __init__(self):
        self._config = {
            "host": None,
            "port": constants.DEFAULT_PORT,
            "name": None,
            "debug": False,
            "forceGuiPrompt": True,
            "noGui": False,
            "noStore": False,
            "room": "",
            "password": None,
            "playerPath": None,
            "file": None,
            "playerArgs": [],
            "playerClass": None,
            "slowOnDesync": True,
            "rewindOnDesync": True,
            "malUsername": "",
            "malPassword": "",
            "malPassword": "",
            "filenamePrivacyMode": constants.PRIVACY_SENDRAW_MODE,
            "filesizePrivacyMode": constants.PRIVACY_SENDRAW_MODE,
            "pauseOnLeave": False,
            "clearGUIData": False
        }

        #
        #Custom validation in self._validateArguments
        #
        self._required = [
            "host",
            "port",
            "name",
            "room",
            "playerPath",
            "playerClass",
        ]

        self._boolean = [
            "debug", "forceGuiPrompt", "noGui", "noStore", "slowOnDesync",
            "pauseOnLeave", "rewindOnDesync", "clearGUIData"
        ]

        self._iniStructure = {
            "server_data": ["host", "port", "password"],
            "client_settings": [
                "name", "room", "playerPath", "slowOnDesync", "rewindOnDesync",
                "forceGuiPrompt", "filenamePrivacyMode", "filesizePrivacyMode",
                "pauseOnLeave"
            ],
            "mal": ["malPassword", "malUsername"]
        }

        #
        #Watch out for the method self._overrideConfigWithArgs when you're adding custom multi-word command line arguments
        #
        self._argparser = argparse.ArgumentParser(
            description=getMessage("en", "argument-description"),
            epilog=getMessage("en", "argument-epilog"))
        self._argparser.add_argument('--no-gui',
                                     action='store_true',
                                     help=getMessage("en", "nogui-argument"))
        self._argparser.add_argument('-a',
                                     '--host',
                                     metavar='hostname',
                                     type=str,
                                     help=getMessage("en", "host-argument"))
        self._argparser.add_argument('-n',
                                     '--name',
                                     metavar='username',
                                     type=str,
                                     help=getMessage("en", "name-argument"))
        self._argparser.add_argument('-d',
                                     '--debug',
                                     action='store_true',
                                     help=getMessage("en", "debug-argument"))
        self._argparser.add_argument('-g',
                                     '--force-gui-prompt',
                                     action='store_true',
                                     help=getMessage(
                                         "en", "force-gui-prompt-argument"))
        self._argparser.add_argument('--no-store',
                                     action='store_true',
                                     help=getMessage("en",
                                                     "no-store-argument"))
        self._argparser.add_argument('-r',
                                     '--room',
                                     metavar='room',
                                     type=str,
                                     nargs='?',
                                     help=getMessage("en", "room-argument"))
        self._argparser.add_argument('-p',
                                     '--password',
                                     metavar='password',
                                     type=str,
                                     nargs='?',
                                     help=getMessage("en",
                                                     "password-argument"))
        self._argparser.add_argument('--player-path',
                                     metavar='path',
                                     type=str,
                                     help=getMessage("en",
                                                     "player-path-argument"))
        self._argparser.add_argument('file',
                                     metavar='file',
                                     type=str,
                                     nargs='?',
                                     help=getMessage("en", "file-argument"))
        self._argparser.add_argument('--clear-gui-data',
                                     action='store_true',
                                     help=getMessage(
                                         "en", "clear-gui-data-argument"))
        self._argparser.add_argument('_args',
                                     metavar='options',
                                     type=str,
                                     nargs='*',
                                     help=getMessage("en", "args-argument"))

        self._playerFactory = PlayerFactory()
예제 #9
0
class ConfigurationGetter(object):
    def __init__(self):
        self._config = {
                        "host": None,
                        "port": constants.DEFAULT_PORT,
                        "name": None,
                        "debug": False,
                        "forceGuiPrompt": True,
                        "noGui": False,
                        "noStore": False,
                        "room": "",
                        "password": None,
                        "playerPath": None,
                        "file": None,
                        "playerArgs": [],
                        "playerClass": None,
                        "slowOnDesync": True,
                        "dontSlowDownWithMe": False,
                        "rewindOnDesync": True,
                        "filenamePrivacyMode": constants.PRIVACY_SENDRAW_MODE,
                        "filesizePrivacyMode": constants.PRIVACY_SENDRAW_MODE,
                        "pauseOnLeave": False,
                        "clearGUIData": False
                        }

        #
        # Custom validation in self._validateArguments
        #
        self._required = [
                          "host",
                          "port",
                          "room",
                          "playerPath",
                          "playerClass",
                         ]

        self._boolean = [
                         "debug",
                         "forceGuiPrompt",
                         "noGui",
                         "noStore",
                         "slowOnDesync",
                         "dontSlowDownWithMe",
                         "pauseOnLeave",
                         "rewindOnDesync",
                         "clearGUIData"
                        ]

        self._iniStructure = {
                        "server_data": ["host", "port", "password"],
                        "client_settings": ["name", "room", "playerPath", "slowOnDesync", "dontSlowDownWithMe", "rewindOnDesync", "forceGuiPrompt", "filenamePrivacyMode", "filesizePrivacyMode", "pauseOnLeave"],
                        }

        #
        # Watch out for the method self._overrideConfigWithArgs when you're adding custom multi-word command line arguments
        #
        self._argparser = argparse.ArgumentParser(description=getMessage("en", "argument-description"),
                                         epilog=getMessage("en", "argument-epilog"))
        self._argparser.add_argument('--no-gui', action='store_true', help=getMessage("en", "nogui-argument"))
        self._argparser.add_argument('-a', '--host', metavar='hostname', type=str, help=getMessage("en", "host-argument"))
        self._argparser.add_argument('-n', '--name', metavar='username', type=str, help=getMessage("en", "name-argument"))
        self._argparser.add_argument('-d', '--debug', action='store_true', help=getMessage("en", "debug-argument"))
        self._argparser.add_argument('-g', '--force-gui-prompt', action='store_true', help=getMessage("en", "force-gui-prompt-argument"))
        self._argparser.add_argument('--no-store', action='store_true', help=getMessage("en", "no-store-argument"))
        self._argparser.add_argument('-r', '--room', metavar='room', type=str, nargs='?', help=getMessage("en", "room-argument"))
        self._argparser.add_argument('-p', '--password', metavar='password', type=str, nargs='?', help=getMessage("en", "password-argument"))
        self._argparser.add_argument('--player-path', metavar='path', type=str, help=getMessage("en", "player-path-argument"))
        self._argparser.add_argument('file', metavar='file', type=str, nargs='?', help=getMessage("en", "file-argument"))
        self._argparser.add_argument('--clear-gui-data', action='store_true', help=getMessage("en", "clear-gui-data-argument"))
        self._argparser.add_argument('_args', metavar='options', type=str, nargs='*', help=getMessage("en", "args-argument"))

        self._playerFactory = PlayerFactory()

    def _validateArguments(self):
        def _isPortValid(varToTest):
            try:
                if (varToTest == "" or varToTest is None):
                    return False
                if (str(varToTest).isdigit() == False):
                    return False
                varToTest = int(varToTest)
                if (varToTest > 65535 or varToTest < 1):
                    return False
                return True
            except:
                return False
        for key in self._boolean:
            if(self._config[key] == "True"):
                self._config[key] = True
            elif(self._config[key] == "False"):
                self._config[key] = False
        for key in self._required:
            if(key == "playerPath"):
                player = self._playerFactory.getPlayerByPath(self._config["playerPath"])
                if(player):
                    self._config["playerClass"] = player
                else:
                    raise InvalidConfigValue("Player path is not set properly")
                if player.__name__ in ['MpvPlayer', 'MplayerPlayer']:
                    if not self._config['file']:
                        raise InvalidConfigValue("File must be selected before starting your player")
            elif(key == "host"):
                self._config["host"], self._config["port"] = self._splitPortAndHost(self._config["host"])
                hostNotValid = (self._config["host"] == "" or self._config["host"] is None)
                portNotValid = (_isPortValid(self._config["port"]) == False)
                if(hostNotValid):
                    raise InvalidConfigValue("Hostname can't be empty")
                elif(portNotValid):
                    raise InvalidConfigValue("Port must be valid")
            elif(self._config[key] == "" or self._config[key] is None):
                raise InvalidConfigValue("{} can't be empty".format(key.capitalize()))

    def _overrideConfigWithArgs(self, args):
        for key, val in vars(args).items():
            if(val):
                if(key == "force_gui_prompt"):
                    key = "forceGuiPrompt"
                if(key == "no_store"):
                    key = "noStore"
                if(key == "player_path"):
                    key = "playerPath"
                if(key == "_args"):
                    key = "playerArgs"
                if(key == "no_gui"):
                    key = "noGui"
                if(key == "clear_gui_data"):
                    key = "clearGUIData"
                self._config[key] = val

    def _splitPortAndHost(self, host):
        port = constants.DEFAULT_PORT if not self._config["port"] else self._config["port"]
        if(host):
            if ':' in host:
                host, port = host.split(':', 1)
                try:
                    port = int(port)
                except ValueError:
                    try:
                        port = port.encode('ascii', 'ignore')
                    except:
                        port = ""
        return host, port

    def _checkForPortableFile(self):
        path = utils.findWorkingDir()
        for name in constants.CONFIG_NAMES:
            if(os.path.isfile(os.path.join(path, name))):
                return os.path.join(path, name)

    def _getConfigurationFilePath(self):
        configFile = self._checkForPortableFile()
        if not configFile:
            for name in constants.CONFIG_NAMES:
                if(configFile and os.path.isfile(configFile)):
                    break
                if(os.name <> 'nt'):
                    configFile = os.path.join(os.getenv('HOME', '.'), name)
                else:
                    configFile = os.path.join(os.getenv('APPDATA', '.'), name)
            if(configFile and not os.path.isfile(configFile)):
                if(os.name <> 'nt'):
                    configFile = os.path.join(os.getenv('HOME', '.'), constants.DEFAULT_CONFIG_NAME_LINUX)
                else:
                    configFile = os.path.join(os.getenv('APPDATA', '.'), constants.DEFAULT_CONFIG_NAME_WINDOWS)

        return configFile

    def _parseConfigFile(self, iniPath, createConfig=True):
        parser = SafeConfigParserUnicode()
        if(not os.path.isfile(iniPath)):
            if(createConfig):
                open(iniPath, 'w').close()
            else:
                return
        parser.readfp(codecs.open(iniPath, "r", "utf_8_sig"))
        for section, options in self._iniStructure.items():
            if(parser.has_section(section)):
                for option in options:
                    if(parser.has_option(section, option)):
                        self._config[option] = parser.get(section, option)

    def _checkConfig(self):
        try:
            self._validateArguments()
        except InvalidConfigValue as e:
            try:
                for key, value in self._promptForMissingArguments(e.message).items():
                    self._config[key] = value
                self._checkConfig()
            except:
                sys.exit()

    def _promptForMissingArguments(self, error=None):
        if(self._config['noGui']):
            print getMessage("en", "missing-arguments-error")
            sys.exit()
        elif(GuiConfiguration):
            gc = GuiConfiguration(self._config, error=error)
            gc.setAvailablePaths(self._playerFactory.getAvailablePlayerPaths())
            gc.run()
            return gc.getProcessedConfiguration()

    def __wasOptionChanged(self, parser, section, option):
        if (parser.has_option(section, option)):
            if (parser.get(section, option) != unicode(self._config[option])):
                return True
        else:
            return True

    def _saveConfig(self, iniPath):
        changed = False
        if(self._config['noStore']):
            return
        parser = SafeConfigParserUnicode()
        parser.readfp(codecs.open(iniPath, "r", "utf_8_sig"))
        for section, options in self._iniStructure.items():
            if(not parser.has_section(section)):
                parser.add_section(section)
                changed = True
            for option in options:
                if(self.__wasOptionChanged(parser, section, option)):
                    changed = True
                parser.set(section, option, unicode(self._config[option]).replace('%', '%%'))
        if(changed):
            parser.write(codecs.open(iniPath, "wb", "utf_8_sig"))


    def _forceGuiPrompt(self):
        try:
            self._validateArguments()
        except InvalidConfigValue:
            pass
        try:
            if(self._config['noGui'] == False):
                for key, value in self._promptForMissingArguments().items():
                    self._config[key] = value
        except GuiConfiguration.WindowClosed:
            sys.exit()


    def __getRelativeConfigLocations(self):
        locations = []
        path = os.path.dirname(os.path.realpath(self._config['file']))
        locations.append(path)
        while path != os.path.dirname(path):
            path = os.path.dirname(path)
            locations.append(path)
        locations.reverse()
        return locations

    def _loadRelativeConfiguration(self):
        locations = self.__getRelativeConfigLocations()
        loadedPaths = []
        for location in locations:
            for name in constants.CONFIG_NAMES:
                path = location + os.path.sep + name
                if(os.path.isfile(path) and (os.name == 'nt' or path != os.path.join(os.getenv('HOME', '.'), constants.DEFAULT_CONFIG_NAME_LINUX))):
                    loadedPaths.append("'" + os.path.normpath(path) + "'")
                    self._parseConfigFile(path, createConfig=False)
                    self._checkConfig()
        return loadedPaths

    def getConfiguration(self):
        iniPath = self._getConfigurationFilePath()
        self._parseConfigFile(iniPath)
        args = self._argparser.parse_args()
        self._overrideConfigWithArgs(args)
        # Arguments not validated yet - booleans are still text values
        if(self._config['forceGuiPrompt'] == "True" or not self._config['file']):
            self._forceGuiPrompt()
        self._checkConfig()
        self._saveConfig(iniPath)
        if(self._config['file']):
            self._config['loadedRelativePaths'] = self._loadRelativeConfiguration()
        if(not self._config['noGui']):
            from syncplay.vendor import qt4reactor
            if QCoreApplication.instance() is None:
                self.app = QtGui.QApplication(sys.argv)
            qt4reactor.install()
        return self._config
예제 #10
0
    def __init__(self):
        self._config = {
            "host": None,
            "port": constants.DEFAULT_PORT,
            "name": None,
            "debug": False,
            "forceGuiPrompt": True,
            "noGui": False,
            "noStore": False,
            "room": "",
            "password": None,
            "playerPath": None,
            "file": None,
            "playerArgs": [],
            "playerClass": None,
            "slowdownThreshold": constants.DEFAULT_SLOWDOWN_KICKIN_THRESHOLD,
            "rewindThreshold": constants.DEFAULT_REWIND_THRESHOLD,
            "rewindOnDesync": True,
            "slowOnDesync": True,
            "dontSlowDownWithMe": False,
            "filenamePrivacyMode": constants.PRIVACY_SENDRAW_MODE,
            "filesizePrivacyMode": constants.PRIVACY_SENDRAW_MODE,
            "pauseOnLeave": False,
            "clearGUIData": False,
            "language": "",
            "resetConfig": False,
            "showOSD": True,
            "showOSDWarnings": True,
            "showSlowdownOSD": True,
            "showDifferentRoomOSD": False,
            "showSameRoomOSD": True,
            "showContactInfo": True,
            "showButtonLabels": True,
            "showTooltips": True,
            "showDurationNotification": True,
        }

        self._defaultConfig = self._config.copy()

        #
        # Custom validation in self._validateArguments
        #
        self._required = ["host", "port", "room", "playerPath", "playerClass"]

        self._boolean = [
            "debug",
            "forceGuiPrompt",
            "noGui",
            "noStore",
            "dontSlowDownWithMe",
            "pauseOnLeave",
            "clearGUIData",
            "rewindOnDesync",
            "slowOnDesync",
            "pauseOnLeave",
            "clearGUIData",
            "resetConfig",
            "showOSD",
            "showOSDWarnings",
            "showSlowdownOSD",
            "showDifferentRoomOSD",
            "showSameRoomOSD",
            "showContactInfo",
            "showButtonLabels",
            "showTooltips",
            "showDurationNotification",
        ]

        self._numeric = ["slowdownThreshold", "rewindThreshold"]

        self._iniStructure = {
            "server_data": ["host", "port", "password"],
            "client_settings": [
                "name",
                "room",
                "playerPath",
                "slowdownThreshold",
                "rewindThreshold",
                "slowOnDesync",
                "rewindOnDesync",
                "dontSlowDownWithMe",
                "forceGuiPrompt",
                "filenamePrivacyMode",
                "filesizePrivacyMode",
                "pauseOnLeave",
            ],
            "gui": [
                "showOSD",
                "showOSDWarnings",
                "showSlowdownOSD",
                "showDifferentRoomOSD",
                "showSameRoomOSD",
                "showContactInfo",
                "showButtonLabels",
                "showTooltips",
                "showDurationNotification",
            ],
            "general": ["language"],
        }

        self._playerFactory = PlayerFactory()
예제 #11
0
class ConfigurationGetter(object):
    def __init__(self):
        self._config = {
            "host": None,
            "port": constants.DEFAULT_PORT,
            "name": None,
            "debug": False,
            "forceGuiPrompt": True,
            "noGui": False,
            "noStore": False,
            "room": "",
            "password": None,
            "playerPath": None,
            "file": None,
            "playerArgs": [],
            "playerClass": None,
            "slowdownThreshold": constants.DEFAULT_SLOWDOWN_KICKIN_THRESHOLD,
            "rewindThreshold": constants.DEFAULT_REWIND_THRESHOLD,
            "rewindOnDesync": True,
            "slowOnDesync": True,
            "dontSlowDownWithMe": False,
            "filenamePrivacyMode": constants.PRIVACY_SENDRAW_MODE,
            "filesizePrivacyMode": constants.PRIVACY_SENDRAW_MODE,
            "pauseOnLeave": False,
            "clearGUIData": False,
            "language": "",
            "resetConfig": False,
            "showOSD": True,
            "showOSDWarnings": True,
            "showSlowdownOSD": True,
            "showDifferentRoomOSD": False,
            "showSameRoomOSD": True,
            "showContactInfo": True,
            "showButtonLabels": True,
            "showTooltips": True,
            "showDurationNotification": True,
        }

        self._defaultConfig = self._config.copy()

        #
        # Custom validation in self._validateArguments
        #
        self._required = ["host", "port", "room", "playerPath", "playerClass"]

        self._boolean = [
            "debug",
            "forceGuiPrompt",
            "noGui",
            "noStore",
            "dontSlowDownWithMe",
            "pauseOnLeave",
            "clearGUIData",
            "rewindOnDesync",
            "slowOnDesync",
            "pauseOnLeave",
            "clearGUIData",
            "resetConfig",
            "showOSD",
            "showOSDWarnings",
            "showSlowdownOSD",
            "showDifferentRoomOSD",
            "showSameRoomOSD",
            "showContactInfo",
            "showButtonLabels",
            "showTooltips",
            "showDurationNotification",
        ]

        self._numeric = ["slowdownThreshold", "rewindThreshold"]

        self._iniStructure = {
            "server_data": ["host", "port", "password"],
            "client_settings": [
                "name",
                "room",
                "playerPath",
                "slowdownThreshold",
                "rewindThreshold",
                "slowOnDesync",
                "rewindOnDesync",
                "dontSlowDownWithMe",
                "forceGuiPrompt",
                "filenamePrivacyMode",
                "filesizePrivacyMode",
                "pauseOnLeave",
            ],
            "gui": [
                "showOSD",
                "showOSDWarnings",
                "showSlowdownOSD",
                "showDifferentRoomOSD",
                "showSameRoomOSD",
                "showContactInfo",
                "showButtonLabels",
                "showTooltips",
                "showDurationNotification",
            ],
            "general": ["language"],
        }

        self._playerFactory = PlayerFactory()

    def _validateArguments(self):
        if self._config["resetConfig"]:
            language = self._config["language"]
            self._config = self._defaultConfig
            self._config["language"] = language
            raise InvalidConfigValue("*" + getMessage("config-cleared-notification"))

        def _isPortValid(varToTest):
            try:
                if varToTest == "" or varToTest is None:
                    return False
                if str(varToTest).isdigit() == False:
                    return False
                varToTest = int(varToTest)
                if varToTest > 65535 or varToTest < 1:
                    return False
                return True
            except:
                return False

        for key in self._boolean:
            if self._config[key] == "True":
                self._config[key] = True
            elif self._config[key] == "False":
                self._config[key] = False

        for key in self._numeric:
            self._config[key] = float(self._config[key])

        for key in self._required:
            if key == "playerPath":
                player = None
                if self._config["playerPath"]:
                    player = self._playerFactory.getPlayerByPath(self._config["playerPath"])
                if player:
                    self._config["playerClass"] = player
                else:
                    raise InvalidConfigValue("Player path is not set properly")
                if player.__name__ in ["MpvPlayer", "MplayerPlayer"]:
                    if not self._config["file"]:
                        raise InvalidConfigValue("File must be selected before starting your player")
            elif key == "host":
                self._config["host"], self._config["port"] = self._splitPortAndHost(self._config["host"])
                hostNotValid = self._config["host"] == "" or self._config["host"] is None
                portNotValid = _isPortValid(self._config["port"]) == False
                if hostNotValid:
                    raise InvalidConfigValue("Hostname can't be empty")
                elif portNotValid:
                    raise InvalidConfigValue("Port must be valid")
            elif self._config[key] == "" or self._config[key] is None:
                raise InvalidConfigValue("{} can't be empty".format(key.capitalize()))

    def _overrideConfigWithArgs(self, args):
        for key, val in vars(args).items():
            if val:
                if key == "force_gui_prompt":
                    key = "forceGuiPrompt"
                if key == "no_store":
                    key = "noStore"
                if key == "player_path":
                    key = "playerPath"
                if key == "_args":
                    key = "playerArgs"
                if key == "no_gui":
                    key = "noGui"
                if key == "clear_gui_data":
                    key = "clearGUIData"
                self._config[key] = val

    def _splitPortAndHost(self, host):
        port = constants.DEFAULT_PORT if not self._config["port"] else self._config["port"]
        if host:
            if ":" in host:
                host, port = host.split(":", 1)
                try:
                    port = int(port)
                except ValueError:
                    try:
                        port = port.encode("ascii", "ignore")
                    except:
                        port = ""
        return host, port

    def _checkForPortableFile(self):
        path = utils.findWorkingDir()
        for name in constants.CONFIG_NAMES:
            if os.path.isfile(os.path.join(path, name)):
                return os.path.join(path, name)

    def _getConfigurationFilePath(self):
        configFile = self._checkForPortableFile()
        if not configFile:
            for name in constants.CONFIG_NAMES:
                if configFile and os.path.isfile(configFile):
                    break
                if os.name <> "nt":
                    configFile = os.path.join(os.getenv("HOME", "."), name)
                else:
                    configFile = os.path.join(os.getenv("APPDATA", "."), name)
            if configFile and not os.path.isfile(configFile):
                if os.name <> "nt":
                    configFile = os.path.join(os.getenv("HOME", "."), constants.DEFAULT_CONFIG_NAME_LINUX)
                else:
                    configFile = os.path.join(os.getenv("APPDATA", "."), constants.DEFAULT_CONFIG_NAME_WINDOWS)

        return configFile

    def _parseConfigFile(self, iniPath, createConfig=True):
        parser = SafeConfigParserUnicode()
        if not os.path.isfile(iniPath):
            if createConfig:
                open(iniPath, "w").close()
            else:
                return
        parser.readfp(codecs.open(iniPath, "r", "utf_8_sig"))
        for section, options in self._iniStructure.items():
            if parser.has_section(section):
                for option in options:
                    if parser.has_option(section, option):
                        self._config[option] = parser.get(section, option)

    def _checkConfig(self):
        try:
            self._validateArguments()
        except InvalidConfigValue as e:
            try:
                for key, value in self._promptForMissingArguments(e.message).items():
                    self._config[key] = value
                self._checkConfig()
            except:
                sys.exit()

    def _promptForMissingArguments(self, error=None):
        if self._config["noGui"] or not GuiConfiguration:
            if error:
                print "{}!".format(error)
            print getMessage("missing-arguments-error")
            sys.exit()
        elif GuiConfiguration:
            gc = GuiConfiguration(self._config, error=error)
            gc.setAvailablePaths(self._playerFactory.getAvailablePlayerPaths())
            gc.run()
            return gc.getProcessedConfiguration()

    def __wasOptionChanged(self, parser, section, option):
        if parser.has_option(section, option):
            if parser.get(section, option) != unicode(self._config[option]):
                return True
        else:
            return True

    def _saveConfig(self, iniPath):
        changed = False
        if self._config["noStore"]:
            return
        parser = SafeConfigParserUnicode()
        parser.readfp(codecs.open(iniPath, "r", "utf_8_sig"))
        for section, options in self._iniStructure.items():
            if not parser.has_section(section):
                parser.add_section(section)
                changed = True
            for option in options:
                if self.__wasOptionChanged(parser, section, option):
                    changed = True
                parser.set(section, option, unicode(self._config[option]).replace("%", "%%"))
        if changed:
            parser.write(codecs.open(iniPath, "wb", "utf_8_sig"))

    def _forceGuiPrompt(self):
        if GuiConfiguration:
            try:
                self._validateArguments()
            except InvalidConfigValue:
                pass

            try:
                if self._config["noGui"] == False:
                    for key, value in self._promptForMissingArguments().items():
                        self._config[key] = value
            except GuiConfiguration.WindowClosed:
                sys.exit()
        else:
            try:
                self._validateArguments()
            except InvalidConfigValue:
                self._promptForMissingArguments()
                sys.exit()

    def __getRelativeConfigLocations(self):
        locations = []
        path = os.path.dirname(os.path.realpath(self._config["file"]))
        locations.append(path)
        while path != os.path.dirname(path):
            path = os.path.dirname(path)
            locations.append(path)
        locations.reverse()
        return locations

    def _loadRelativeConfiguration(self):
        locations = self.__getRelativeConfigLocations()
        loadedPaths = []
        for location in locations:
            for name in constants.CONFIG_NAMES:
                path = location + os.path.sep + name
                if os.path.isfile(path) and (
                    os.name == "nt" or path != os.path.join(os.getenv("HOME", "."), constants.DEFAULT_CONFIG_NAME_LINUX)
                ):
                    loadedPaths.append("'" + os.path.normpath(path) + "'")
                    self._parseConfigFile(path, createConfig=False)
                    self._checkConfig()
        return loadedPaths

    def getConfiguration(self):
        iniPath = self._getConfigurationFilePath()
        self._parseConfigFile(iniPath)
        #
        # Watch out for the method self._overrideConfigWithArgs when you're adding custom multi-word command line arguments
        #
        if self._config["language"]:
            setLanguage(self._config["language"])
        self._argparser = argparse.ArgumentParser(
            description=getMessage("argument-description"), epilog=getMessage("argument-epilog")
        )
        self._argparser.add_argument("--no-gui", action="store_true", help=getMessage("nogui-argument"))
        self._argparser.add_argument("-a", "--host", metavar="hostname", type=str, help=getMessage("host-argument"))
        self._argparser.add_argument("-n", "--name", metavar="username", type=str, help=getMessage("name-argument"))
        self._argparser.add_argument("-d", "--debug", action="store_true", help=getMessage("debug-argument"))
        self._argparser.add_argument(
            "-g", "--force-gui-prompt", action="store_true", help=getMessage("force-gui-prompt-argument")
        )
        self._argparser.add_argument("--no-store", action="store_true", help=getMessage("no-store-argument"))
        self._argparser.add_argument(
            "-r", "--room", metavar="room", type=str, nargs="?", help=getMessage("room-argument")
        )
        self._argparser.add_argument(
            "-p", "--password", metavar="password", type=str, nargs="?", help=getMessage("password-argument")
        )
        self._argparser.add_argument("--player-path", metavar="path", type=str, help=getMessage("player-path-argument"))
        self._argparser.add_argument("--language", metavar="language", type=str, help=getMessage("language-argument"))
        self._argparser.add_argument("file", metavar="file", type=str, nargs="?", help=getMessage("file-argument"))
        self._argparser.add_argument(
            "--clear-gui-data", action="store_true", help=getMessage("clear-gui-data-argument")
        )
        self._argparser.add_argument("-v", "--version", action="store_true", help=getMessage("version-argument"))
        self._argparser.add_argument("_args", metavar="options", type=str, nargs="*", help=getMessage("args-argument"))
        args = self._argparser.parse_args()
        if args.version:
            print getMessage("version-message").format(version, milestone)
            sys.exit()
        self._overrideConfigWithArgs(args)
        if self._config["file"] and self._config["file"][:2] == "--":
            self._config["playerArgs"].insert(0, self._config["file"])
            self._config["file"] = None
        # Arguments not validated yet - booleans are still text values
        if self._config["language"]:
            setLanguage(self._config["language"])
        if (
            (self._config["forceGuiPrompt"] == "True" or not self._config["file"])
            and GuiConfiguration
            and not self._config["noGui"]
        ):
            self._forceGuiPrompt()
        self._checkConfig()
        self._saveConfig(iniPath)
        if self._config["file"]:
            self._config["loadedRelativePaths"] = self._loadRelativeConfiguration()
        if self._config["language"]:
            setLanguage(self._config["language"])
        if not GuiConfiguration:
            self._config["noGui"] = True
        if not self._config["noGui"]:
            from syncplay.vendor import qt4reactor

            if QCoreApplication.instance() is None:
                self.app = QtGui.QApplication(sys.argv)
            qt4reactor.install()
        return self._config
예제 #12
0
    def __init__(self):
        self._config = {
            "host": None,
            "port": constants.DEFAULT_PORT,
            "name": None,
            "debug": False,
            "forceGuiPrompt": True,
            "noGui": False,
            "noStore": False,
            "room": "",
            "password": None,
            "playerPath": None,
            "perPlayerArguments": None,
            "mediaSearchDirectories": None,
            "sharedPlaylistEnabled": True,
            "loopAtEndOfPlaylist": False,
            "loopSingleFiles": False,
            "onlySwitchToTrustedDomains": True,
            "trustedDomains": constants.DEFAULT_TRUSTED_DOMAINS,
            "file": None,
            "playerArgs": [],
            "playerClass": None,
            "slowdownThreshold": constants.DEFAULT_SLOWDOWN_KICKIN_THRESHOLD,
            "rewindThreshold": constants.DEFAULT_REWIND_THRESHOLD,
            "fastforwardThreshold": constants.DEFAULT_FASTFORWARD_THRESHOLD,
            "rewindOnDesync": True,
            "slowOnDesync": True,
            "fastforwardOnDesync": True,
            "dontSlowDownWithMe": False,
            "filenamePrivacyMode": constants.PRIVACY_SENDRAW_MODE,
            "filesizePrivacyMode": constants.PRIVACY_SENDRAW_MODE,
            "pauseOnLeave": False,
            "readyAtStart": False,
            "unpauseAction": constants.UNPAUSE_IFOTHERSREADY_MODE,
            "autoplayInitialState": None,
            "autoplayMinUsers": -1,
            "autoplayRequireSameFilenames": True,
            "clearGUIData": False,
            "language": "",
            "checkForUpdatesAutomatically": None,
            "lastCheckedForUpdates": "",
            "resetConfig": False,
            "showOSD": True,
            "showOSDWarnings": True,
            "showSlowdownOSD": True,
            "showDifferentRoomOSD": False,
            "showSameRoomOSD": True,
            "showNonControllerOSD": False,
            "showContactInfo": True,
            "showDurationNotification": True,
            "chatInputEnabled": True,
            "chatInputFontFamily": 'sans-serif',
            "chatInputRelativeFontSize": constants.DEFAULT_CHAT_FONT_SIZE,
            "chatInputFontWeight": constants.DEFAULT_CHAT_FONT_WEIGHT,
            "chatInputFontUnderline": False,
            "chatInputFontColor": constants.DEFAULT_CHAT_INPUT_FONT_COLOR,
            "chatInputPosition": constants.INPUT_POSITION_TOP,
            "chatDirectInput": False,
            "chatOutputEnabled": True,
            "chatOutputFontFamily": 'sans-serif',
            "chatOutputRelativeFontSize": constants.DEFAULT_CHAT_FONT_SIZE,
            "chatOutputFontWeight": constants.DEFAULT_CHAT_FONT_WEIGHT,
            "chatOutputFontUnderline": False,
            "chatOutputMode": constants.CHATROOM_MODE,
            "chatMaxLines": 7,
            "chatTopMargin": 25,
            "chatLeftMargin": 20,
            "chatBottomMargin": 30,
            "chatMoveOSD": True,
            "chatOSDMargin": 110,
            "notificationTimeout": 3,
            "alertTimeout": 5,
            "chatTimeout": 7,
            "publicServers": []
        }

        self._defaultConfig = self._config.copy()

        #
        # Custom validation in self._validateArguments
        #
        self._required = [
            "host",
            "port",
            "room",
            "playerPath",
            "playerClass",
        ]

        self._boolean = [
            "debug",
            "forceGuiPrompt",
            "noGui",
            "noStore",
            "dontSlowDownWithMe",
            "pauseOnLeave",
            "readyAtStart",
            "autoplayRequireSameFilenames",
            "clearGUIData",
            "rewindOnDesync",
            "slowOnDesync",
            "fastforwardOnDesync",
            "pauseOnLeave",
            "clearGUIData",
            "resetConfig",
            "showOSD",
            "showOSDWarnings",
            "showSlowdownOSD",
            "showDifferentRoomOSD",
            "showSameRoomOSD",
            "showNonControllerOSD",
            "showDurationNotification",
            "sharedPlaylistEnabled",
            "loopAtEndOfPlaylist",
            "loopSingleFiles",
            "onlySwitchToTrustedDomains",
            "chatInputEnabled",
            "chatInputFontUnderline",
            "chatDirectInput",
            "chatMoveOSD",
            "chatOutputEnabled",
            "chatOutputFontUnderline"
        ]
        self._tristate = [
            "checkForUpdatesAutomatically",
            "autoplayInitialState",
        ]

        self._serialised = [
            "perPlayerArguments",
            "mediaSearchDirectories",
            "trustedDomains",
            "publicServers",
        ]

        self._numeric = [
            "slowdownThreshold",
            "rewindThreshold",
            "fastforwardThreshold",
            "autoplayMinUsers",
            "chatInputRelativeFontSize",
            "chatInputFontWeight",
            "chatOutputFontWeight",
            "chatOutputRelativeFontSize",
            "chatMaxLines",
            "chatTopMargin",
            "chatLeftMargin",
            "chatBottomMargin",
            "chatOSDMargin",
            "notificationTimeout",
            "alertTimeout",
            "chatTimeout"
        ]

        self._hexadecimal = [
            "chatInputFontColor"
        ]

        self._iniStructure = {
            "server_data": ["host", "port", "password"],
            "client_settings": [
                "name", "room", "playerPath",
                "perPlayerArguments", "slowdownThreshold",
                "rewindThreshold", "fastforwardThreshold",
                "slowOnDesync", "rewindOnDesync",
                "fastforwardOnDesync", "dontSlowDownWithMe",
                "forceGuiPrompt", "filenamePrivacyMode",
                "filesizePrivacyMode", "unpauseAction",
                "pauseOnLeave", "readyAtStart", "autoplayMinUsers",
                "autoplayInitialState", "mediaSearchDirectories",
                "sharedPlaylistEnabled", "loopAtEndOfPlaylist",
                "loopSingleFiles",
                "onlySwitchToTrustedDomains", "trustedDomains", "publicServers"],
            "gui": [
                "showOSD", "showOSDWarnings", "showSlowdownOSD",
                "showDifferentRoomOSD", "showSameRoomOSD",
                "showNonControllerOSD", "showDurationNotification",
                "chatInputEnabled", "chatInputFontUnderline",
                "chatInputFontFamily", "chatInputRelativeFontSize",
                "chatInputFontWeight", "chatInputFontColor",
                "chatInputPosition", "chatDirectInput",
                "chatOutputFontFamily", "chatOutputRelativeFontSize",
                "chatOutputFontWeight", "chatOutputFontUnderline",
                "chatOutputMode", "chatMaxLines",
                "chatTopMargin", "chatLeftMargin",
                "chatBottomMargin", "chatDirectInput",
                "chatMoveOSD", "chatOSDMargin",
                "notificationTimeout", "alertTimeout",
                "chatTimeout", "chatOutputEnabled"],
            "general": [
                "language", "checkForUpdatesAutomatically",
                "lastCheckedForUpdates"]
        }

        self._playerFactory = PlayerFactory()
예제 #13
0
class ConfigurationGetter(object):
    def __init__(self):
        self._config = {
            "host": None,
            "port": constants.DEFAULT_PORT,
            "name": None,
            "debug": False,
            "forceGuiPrompt": True,
            "noGui": False,
            "noStore": False,
            "room": "",
            "password": None,
            "playerPath": None,
            "perPlayerArguments": None,
            "mediaSearchDirectories": None,
            "sharedPlaylistEnabled": True,
            "loopAtEndOfPlaylist": False,
            "loopSingleFiles": False,
            "onlySwitchToTrustedDomains": True,
            "trustedDomains": constants.DEFAULT_TRUSTED_DOMAINS,
            "file": None,
            "playerArgs": [],
            "playerClass": None,
            "slowdownThreshold": constants.DEFAULT_SLOWDOWN_KICKIN_THRESHOLD,
            "rewindThreshold": constants.DEFAULT_REWIND_THRESHOLD,
            "fastforwardThreshold": constants.DEFAULT_FASTFORWARD_THRESHOLD,
            "rewindOnDesync": True,
            "slowOnDesync": True,
            "fastforwardOnDesync": True,
            "dontSlowDownWithMe": False,
            "filenamePrivacyMode": constants.PRIVACY_SENDRAW_MODE,
            "filesizePrivacyMode": constants.PRIVACY_SENDRAW_MODE,
            "pauseOnLeave": False,
            "readyAtStart": False,
            "unpauseAction": constants.UNPAUSE_IFOTHERSREADY_MODE,
            "autoplayInitialState": None,
            "autoplayMinUsers": -1,
            "autoplayRequireSameFilenames": True,
            "clearGUIData": False,
            "language": "",
            "checkForUpdatesAutomatically": None,
            "lastCheckedForUpdates": "",
            "resetConfig": False,
            "showOSD": True,
            "showOSDWarnings": True,
            "showSlowdownOSD": True,
            "showDifferentRoomOSD": False,
            "showSameRoomOSD": True,
            "showNonControllerOSD": False,
            "showContactInfo": True,
            "showDurationNotification": True,
            "chatInputEnabled": True,
            "chatInputFontFamily": 'sans-serif',
            "chatInputRelativeFontSize": constants.DEFAULT_CHAT_FONT_SIZE,
            "chatInputFontWeight": constants.DEFAULT_CHAT_FONT_WEIGHT,
            "chatInputFontUnderline": False,
            "chatInputFontColor": constants.DEFAULT_CHAT_INPUT_FONT_COLOR,
            "chatInputPosition": constants.INPUT_POSITION_TOP,
            "chatDirectInput": False,
            "chatOutputEnabled": True,
            "chatOutputFontFamily": 'sans-serif',
            "chatOutputRelativeFontSize": constants.DEFAULT_CHAT_FONT_SIZE,
            "chatOutputFontWeight": constants.DEFAULT_CHAT_FONT_WEIGHT,
            "chatOutputFontUnderline": False,
            "chatOutputMode": constants.CHATROOM_MODE,
            "chatMaxLines": 7,
            "chatTopMargin": 25,
            "chatLeftMargin": 20,
            "chatBottomMargin": 30,
            "chatMoveOSD": True,
            "chatOSDMargin": 110,
            "notificationTimeout": 3,
            "alertTimeout": 5,
            "chatTimeout": 7,
            "publicServers": []
        }

        self._defaultConfig = self._config.copy()

        #
        # Custom validation in self._validateArguments
        #
        self._required = [
            "host",
            "port",
            "room",
            "playerPath",
            "playerClass",
        ]

        self._boolean = [
            "debug",
            "forceGuiPrompt",
            "noGui",
            "noStore",
            "dontSlowDownWithMe",
            "pauseOnLeave",
            "readyAtStart",
            "autoplayRequireSameFilenames",
            "clearGUIData",
            "rewindOnDesync",
            "slowOnDesync",
            "fastforwardOnDesync",
            "pauseOnLeave",
            "clearGUIData",
            "resetConfig",
            "showOSD",
            "showOSDWarnings",
            "showSlowdownOSD",
            "showDifferentRoomOSD",
            "showSameRoomOSD",
            "showNonControllerOSD",
            "showDurationNotification",
            "sharedPlaylistEnabled",
            "loopAtEndOfPlaylist",
            "loopSingleFiles",
            "onlySwitchToTrustedDomains",
            "chatInputEnabled",
            "chatInputFontUnderline",
            "chatDirectInput",
            "chatMoveOSD",
            "chatOutputEnabled",
            "chatOutputFontUnderline"
        ]
        self._tristate = [
            "checkForUpdatesAutomatically",
            "autoplayInitialState",
        ]

        self._serialised = [
            "perPlayerArguments",
            "mediaSearchDirectories",
            "trustedDomains",
            "publicServers",
        ]

        self._numeric = [
            "slowdownThreshold",
            "rewindThreshold",
            "fastforwardThreshold",
            "autoplayMinUsers",
            "chatInputRelativeFontSize",
            "chatInputFontWeight",
            "chatOutputFontWeight",
            "chatOutputRelativeFontSize",
            "chatMaxLines",
            "chatTopMargin",
            "chatLeftMargin",
            "chatBottomMargin",
            "chatOSDMargin",
            "notificationTimeout",
            "alertTimeout",
            "chatTimeout"
        ]

        self._hexadecimal = [
            "chatInputFontColor"
        ]

        self._iniStructure = {
            "server_data": ["host", "port", "password"],
            "client_settings": [
                "name", "room", "playerPath",
                "perPlayerArguments", "slowdownThreshold",
                "rewindThreshold", "fastforwardThreshold",
                "slowOnDesync", "rewindOnDesync",
                "fastforwardOnDesync", "dontSlowDownWithMe",
                "forceGuiPrompt", "filenamePrivacyMode",
                "filesizePrivacyMode", "unpauseAction",
                "pauseOnLeave", "readyAtStart", "autoplayMinUsers",
                "autoplayInitialState", "mediaSearchDirectories",
                "sharedPlaylistEnabled", "loopAtEndOfPlaylist",
                "loopSingleFiles",
                "onlySwitchToTrustedDomains", "trustedDomains", "publicServers"],
            "gui": [
                "showOSD", "showOSDWarnings", "showSlowdownOSD",
                "showDifferentRoomOSD", "showSameRoomOSD",
                "showNonControllerOSD", "showDurationNotification",
                "chatInputEnabled", "chatInputFontUnderline",
                "chatInputFontFamily", "chatInputRelativeFontSize",
                "chatInputFontWeight", "chatInputFontColor",
                "chatInputPosition", "chatDirectInput",
                "chatOutputFontFamily", "chatOutputRelativeFontSize",
                "chatOutputFontWeight", "chatOutputFontUnderline",
                "chatOutputMode", "chatMaxLines",
                "chatTopMargin", "chatLeftMargin",
                "chatBottomMargin", "chatDirectInput",
                "chatMoveOSD", "chatOSDMargin",
                "notificationTimeout", "alertTimeout",
                "chatTimeout", "chatOutputEnabled"],
            "general": [
                "language", "checkForUpdatesAutomatically",
                "lastCheckedForUpdates"]
        }

        self._playerFactory = PlayerFactory()

    def _validateArguments(self):
        if self._config['resetConfig']:
            language = self._config['language']
            checkForUpdatesAutomatically = self._config['checkForUpdatesAutomatically']
            self._config = self._defaultConfig
            self._config['language'] = language
            self._config['checkForUpdatesAutomatically'] = checkForUpdatesAutomatically
            raise InvalidConfigValue("*" + getMessage("config-cleared-notification"))

        if not isValidLanguage(self._config['language']):
            self._config['language'] = ""

        def _isPortValid(varToTest):
            try:
                if varToTest == "" or varToTest is None:
                    return False
                if not str(varToTest).isdigit():
                    return False
                varToTest = int(varToTest)
                if varToTest > 65535 or varToTest < 1:
                    return False
                return True
            except:
                return False

        for key in self._boolean:
            if self._config[key] == "True":
                self._config[key] = True
            elif self._config[key] == "False":
                self._config[key] = False

        for key in self._serialised:
            if self._config[key] is None or self._config[key] == "":
                self._config[key] = {}
            elif isinstance(self._config[key], str):
                self._config[key] = ast.literal_eval(self._config[key])

        for key in self._tristate:
            if self._config[key] == "True":
                self._config[key] = True
            elif self._config[key] == "False":
                self._config[key] = False
            elif self._config[key] == "None":
                self._config[key] = None

        for key in self._numeric:
            self._config[key] = float(self._config[key])

        for key in self._hexadecimal:
            match = re.search(r'^#(?:[0-9a-fA-F]){6}$', self._config[key])
            if not match:
                self._config[key] = "#FFFFFF"

        for key in self._required:
            if key == "playerPath":
                player = None
                if self._config["playerPath"]:
                    player = self._playerFactory.getPlayerByPath(self._config["playerPath"])
                if player:
                    self._config["playerClass"] = player
                else:
                    raise InvalidConfigValue(getMessage("player-path-config-error"))
                playerPathErrors = player.getPlayerPathErrors(
                    self._config["playerPath"], self._config['file'] if self._config['file'] else None)
                if playerPathErrors:
                    raise InvalidConfigValue(playerPathErrors)
            elif key == "host":
                self._config["host"], self._config["port"] = self._splitPortAndHost(self._config["host"])
                hostNotValid = (self._config["host"] == "" or self._config["host"] is None)
                portNotValid = (_isPortValid(self._config["port"]) == False)
                if hostNotValid:
                    raise InvalidConfigValue(getMessage("no-hostname-config-error"))
                elif portNotValid:
                    raise InvalidConfigValue(getMessage("invalid-port-config-error"))
            elif self._config[key] == "" or self._config[key] is None:
                raise InvalidConfigValue(getMessage("empty-value-config-error").format(key.capitalize()))

    def _overrideConfigWithArgs(self, args):
        for key, val in list(vars(args).items()):
            if val:
                if key == "force_gui_prompt":
                    key = "forceGuiPrompt"
                if key == "no_store":
                    key = "noStore"
                if key == "player_path":
                    key = "playerPath"
                if key == "_args":
                    key = "playerArgs"
                if key == "no_gui":
                    key = "noGui"
                if key == "clear_gui_data":
                    key = "clearGUIData"
                self._config[key] = val

    def _splitPortAndHost(self, host):
        port = constants.DEFAULT_PORT if not self._config["port"] else self._config["port"]
        if host:
            if ':' in host:
                if host.count(':') == 1:
                    #IPv4 address or hostname, with port
                    host, port = host.rsplit(':', 1)
                    try:
                        port = int(port)
                    except ValueError:
                        try:
                            port = port.encode('ascii', 'ignore')
                        except:
                            port = ""
                else:
                    #IPv6 address
                    if ']' in host:
                        #IPv6 address in brackets
                        endBracket = host.index(']')
                        try:
                            #port explicitely indicated
                            port = int(host[endBracket+2:])
                        except ValueError:
                            #no port after the bracket
                            pass
                        host = host[:endBracket+1]
                    else:
                        #IPv6 address with no port and no brackets
                        #add brackets to correctly store IPv6 addresses in configs
                        host = '[' + host + ']'
        return host, port

    def _checkForPortableFile(self):
        path = utils.findWorkingDir()
        for name in constants.CONFIG_NAMES:
            if os.path.isfile(os.path.join(path, name)):
                return os.path.join(path, name)

    def _getConfigurationFilePath(self):
        configFile = self._checkForPortableFile()
        if configFile:
            return configFile
        for name in constants.CONFIG_NAMES:
            configFile = self._expandConfigPath(name, xdg=False)
            if os.path.isfile(configFile):
                return configFile
        return self._expandConfigPath()

    def _expandConfigPath(self, name=None, xdg=True):
        if os.name != 'nt':
            if xdg:
                prefix = self._getXdgConfigHome()
            else:
                prefix = os.getenv('HOME', '.')
        else:
            prefix = os.getenv('APPDATA', '.')
        return os.path.join(prefix, name or constants.DEFAULT_CONFIG_NAME)

    def _getXdgConfigHome(self):
        path = os.getenv('XDG_CONFIG_HOME', os.path.expanduser('~/.config'))
        if not os.path.isdir(path):
            os.mkdir(path, 0o700)
        return path

    def _parseConfigFile(self, iniPath, createConfig=True):
        parser = SafeConfigParserUnicode(strict=False)
        if not os.path.isfile(iniPath):
            if createConfig:
                open(iniPath, 'w').close()
            else:
                return
        parser.readfp(codecs.open(iniPath, "r", "utf_8_sig"))
        for section, options in list(self._iniStructure.items()):
            if parser.has_section(section):
                for option in options:
                    if parser.has_option(section, option):
                        self._config[option] = parser.get(section, option)

    def _checkConfig(self):
        try:
            self._validateArguments()
        except InvalidConfigValue as e:
            try:
                for key, value in list(self._promptForMissingArguments(e).items()):
                    self._config[key] = value
                self._checkConfig()
            except:
                sys.exit()

    def _promptForMissingArguments(self, error=None):
        if self._config['noGui']:
            if error:
                print("{}!".format(error))
            print(getMessage("missing-arguments-error"))
            sys.exit()
        else:
            from syncplay.ui.GuiConfiguration import GuiConfiguration
            gc = GuiConfiguration(self._config, error=error)
            gc.setAvailablePaths(self._playerFactory.getAvailablePlayerPaths())
            gc.run()
            return gc.getProcessedConfiguration()

    def __wasOptionChanged(self, parser, section, option):
        if parser.has_option(section, option):
            if parser.get(section, option) != str(self._config[option]):
                return True
        else:
            return True

    def _saveConfig(self, iniPath):
        changed = False
        if self._config['noStore']:
            return
        parser = SafeConfigParserUnicode(strict=False)
        parser.readfp(codecs.open(iniPath, "r", "utf_8_sig"))
        for section, options in list(self._iniStructure.items()):
            if not parser.has_section(section):
                parser.add_section(section)
                changed = True
            for option in options:
                if self.__wasOptionChanged(parser, section, option):
                    changed = True
                parser.set(section, option, str(self._config[option]).replace('%', '%%'))
        if changed:
            parser.write(codecs.open(iniPath, "wb", "utf_8_sig"))

    def _forceGuiPrompt(self):
        from syncplay.ui.GuiConfiguration import GuiConfiguration
        try:
            self._validateArguments()
        except InvalidConfigValue:
            pass

        try:
            for key, value in list(self._promptForMissingArguments().items()):
                self._config[key] = value
        except GuiConfiguration.WindowClosed:
            sys.exit()

    def __getRelativeConfigLocations(self):
        locations = []
        path = os.path.dirname(os.path.realpath(self._config['file']))
        locations.append(path)
        while path != os.path.dirname(path):
            path = os.path.dirname(path)
            locations.append(path)
        locations.reverse()
        return locations

    def _loadRelativeConfiguration(self):
        locations = self.__getRelativeConfigLocations()
        loadedPaths = []
        for location in locations:
            for name in constants.CONFIG_NAMES:
                path = location + os.path.sep + name
                if os.path.isfile(path) and (os.name == 'nt' or path != os.path.join(os.getenv('HOME', '.'), name)):
                    loadedPaths.append("'{}'".format(os.path.normpath(path)))
                    self._parseConfigFile(path, createConfig=False)
                    self._checkConfig()
        return loadedPaths

    def getConfiguration(self):
        iniPath = self._getConfigurationFilePath()
        self._parseConfigFile(iniPath)
        #
        # Watch out for the method self._overrideConfigWithArgs when you're adding custom multi-word command line arguments
        #
        if self._config['language']:
            setLanguage(self._config['language'])
        self._argparser = argparse.ArgumentParser(
            description=getMessage("argument-description"),
            epilog=getMessage("argument-epilog"))
        self._argparser.add_argument('--no-gui', action='store_true', help=getMessage("nogui-argument"))
        self._argparser.add_argument('-a', '--host', metavar='hostname', type=str, help=getMessage("host-argument"))
        self._argparser.add_argument('-n', '--name', metavar='username', type=str, help=getMessage("name-argument"))
        self._argparser.add_argument('-d', '--debug', action='store_true', help=getMessage("debug-argument"))
        self._argparser.add_argument('-g', '--force-gui-prompt', action='store_true', help=getMessage("force-gui-prompt-argument"))
        self._argparser.add_argument('--no-store', action='store_true', help=getMessage("no-store-argument"))
        self._argparser.add_argument('-r', '--room', metavar='room', type=str, nargs='?', help=getMessage("room-argument"))
        self._argparser.add_argument('-p', '--password', metavar='password', type=str, nargs='?', help=getMessage("password-argument"))
        self._argparser.add_argument('--player-path', metavar='path', type=str, help=getMessage("player-path-argument"))
        self._argparser.add_argument('--language', metavar='language', type=str, help=getMessage("language-argument"))
        self._argparser.add_argument('file', metavar='file', type=str, nargs='?', help=getMessage("file-argument"))
        self._argparser.add_argument('--clear-gui-data', action='store_true', help=getMessage("clear-gui-data-argument"))
        self._argparser.add_argument('-v', '--version', action='store_true', help=getMessage("version-argument"))
        self._argparser.add_argument('_args', metavar='options', type=str, nargs='*', help=getMessage("args-argument"))
        args = self._argparser.parse_args()
        if args.version:
            print(getMessage("version-message").format(version, milestone))
            sys.exit()
        self._overrideConfigWithArgs(args)
        if not self._config['noGui']:
            try:
                from syncplay.vendor.Qt import QtWidgets, IsPySide, IsPySide2
                from syncplay.vendor.Qt.QtCore import QCoreApplication
                from syncplay.vendor import qt5reactor
                if not (IsPySide2 or IsPySide):
                    raise ImportError
                if QCoreApplication.instance() is None:
                    self.app = QtWidgets.QApplication(sys.argv)
                qt5reactor.install()
                if isMacOS():
                    import appnope
                    appnope.nope()
            except ImportError:
                try:
                    from twisted.trial import unittest
                except Exception as e:
                    print(e)
                    print(getMessage("unable-import-twisted-error"))
                    sys.exit()
                print(getMessage("unable-import-gui-error"))
                self._config['noGui'] = True
        if self._config['file'] and self._config['file'][:2] == "--":
            self._config['playerArgs'].insert(0, self._config['file'])
            self._config['file'] = None
        # Arguments not validated yet - booleans are still text values
        if self._config['language']:
            setLanguage(self._config['language'])
        if (self._config['forceGuiPrompt'] == "True" or not self._config['file']) and not self._config['noGui']:
            self._forceGuiPrompt()
        self._checkConfig()
        self._saveConfig(iniPath)
        if self._config['file']:
            self._config['loadedRelativePaths'] = self._loadRelativeConfiguration()
        if self._config['language']:
            setLanguage(self._config['language'])
        return self._config

    def setConfigOption(self, option, value):
        path = self._getConfigurationFilePath()
        backup = self._config.copy()
        self._parseConfigFile(path)
        self._config[option] = value
        backup[option] = value
        self._saveConfig(path)
        self._config = backup
예제 #14
0
    def __init__(self):
        self._config = {
                        "host": None,
                        "port": constants.DEFAULT_PORT,
                        "name": None,
                        "debug": False,
                        "forceGuiPrompt": True,
                        "noGui": False,
                        "noStore": False,
                        "room": "",
                        "password": None,
                        "playerPath": None,
                        "perPlayerArguments": None,
                        "mediaSearchDirectories": None,
                        "file": None,
                        "playerArgs": [],
                        "playerClass": None,
                        "slowdownThreshold": constants.DEFAULT_SLOWDOWN_KICKIN_THRESHOLD,
                        "rewindThreshold": constants.DEFAULT_REWIND_THRESHOLD,
                        "fastforwardThreshold": constants.DEFAULT_FASTFORWARD_THRESHOLD,
                        "rewindOnDesync": True,
                        "slowOnDesync": True,
                        "fastforwardOnDesync": True,
                        "dontSlowDownWithMe": False,
                        "filenamePrivacyMode": constants.PRIVACY_SENDRAW_MODE,
                        "filesizePrivacyMode": constants.PRIVACY_SENDRAW_MODE,
                        "pauseOnLeave": False,
                        "readyAtStart": False,
                        "unpauseAction": constants.UNPAUSE_IFOTHERSREADY_MODE,
                        "autoplayInitialState" : None,
                        "autoplayMinUsers" : -1,
                        "clearGUIData": False,
                        "language" : "",
                        "checkForUpdatesAutomatically" : None,
                        "lastCheckedForUpdates" : "",
                        "resetConfig" : False,
                        "showOSD" : True,
                        "showOSDWarnings" : True,
                        "showSlowdownOSD" : True,
                        "showDifferentRoomOSD" : False,
                        "showSameRoomOSD" : True,
                        "showNonControllerOSD" : False,
                        "showContactInfo" : True,
                        "showDurationNotification" : True
                        }

        self._defaultConfig = self._config.copy()

        #
        # Custom validation in self._validateArguments
        #
        self._required = [
                          "host",
                          "port",
                          "room",
                          "playerPath",
                          "playerClass",
                         ]

        self._boolean = [
                         "debug",
                         "forceGuiPrompt",
                         "noGui",
                         "noStore",
                         "dontSlowDownWithMe",
                         "pauseOnLeave",
                         "readyAtStart",
                         "clearGUIData",
                         "rewindOnDesync",
                         "slowOnDesync",
                         "fastforwardOnDesync",
                         "pauseOnLeave",
                         "clearGUIData",
                         "resetConfig",
                         "showOSD",
                         "showOSDWarnings",
                         "showSlowdownOSD",
                         "showDifferentRoomOSD",
                         "showSameRoomOSD",
                         "showNonControllerOSD",
                         "showDurationNotification"
                        ]
        self._tristate = [
            "checkForUpdatesAutomatically",
            "autoplayInitialState",
        ]

        self._serialised = [
            "perPlayerArguments",
            "mediaSearchDirectories",
        ]

        self._numeric = [
            "slowdownThreshold",
            "rewindThreshold",
            "fastforwardThreshold",
            "autoplayMinUsers",
        ]

        self._iniStructure = {
                        "server_data": ["host", "port", "password"],
                        "client_settings": ["name", "room", "playerPath", "perPlayerArguments", "slowdownThreshold", "rewindThreshold", "fastforwardThreshold", "slowOnDesync", "rewindOnDesync", "fastforwardOnDesync", "dontSlowDownWithMe", "forceGuiPrompt", "filenamePrivacyMode", "filesizePrivacyMode", "unpauseAction", "pauseOnLeave", "readyAtStart", "autoplayMinUsers", "autoplayInitialState", "mediaSearchDirectories"],
                        "gui": ["showOSD", "showOSDWarnings", "showSlowdownOSD", "showDifferentRoomOSD", "showSameRoomOSD", "showNonControllerOSD", "showDurationNotification"],
                        "general": ["language", "checkForUpdatesAutomatically", "lastCheckedForUpdates"]
                        }

        self._playerFactory = PlayerFactory()
예제 #15
0
class ConfigurationGetter(object):
    def __init__(self):
        self._config = {
            "host": None,
            "port": constants.DEFAULT_PORT,
            "name": None,
            "debug": False,
            "forceGuiPrompt": True,
            "noGui": False,
            "noStore": False,
            "room": "",
            "password": None,
            "playerPath": None,
            "file": None,
            "playerArgs": [],
            "playerClass": None,
            "slowOnDesync": True,
            "rewindOnDesync": True,
            "malUsername": "",
            "malPassword": "",
            "malPassword": "",
            "filenamePrivacyMode": constants.PRIVACY_SENDRAW_MODE,
            "filesizePrivacyMode": constants.PRIVACY_SENDRAW_MODE,
            "pauseOnLeave": False,
            "clearGUIData": False
        }

        #
        #Custom validation in self._validateArguments
        #
        self._required = [
            "host",
            "port",
            "name",
            "room",
            "playerPath",
            "playerClass",
        ]

        self._boolean = [
            "debug", "forceGuiPrompt", "noGui", "noStore", "slowOnDesync",
            "pauseOnLeave", "rewindOnDesync", "clearGUIData"
        ]

        self._iniStructure = {
            "server_data": ["host", "port", "password"],
            "client_settings": [
                "name", "room", "playerPath", "slowOnDesync", "rewindOnDesync",
                "forceGuiPrompt", "filenamePrivacyMode", "filesizePrivacyMode",
                "pauseOnLeave"
            ],
            "mal": ["malPassword", "malUsername"]
        }

        #
        #Watch out for the method self._overrideConfigWithArgs when you're adding custom multi-word command line arguments
        #
        self._argparser = argparse.ArgumentParser(
            description=getMessage("en", "argument-description"),
            epilog=getMessage("en", "argument-epilog"))
        self._argparser.add_argument('--no-gui',
                                     action='store_true',
                                     help=getMessage("en", "nogui-argument"))
        self._argparser.add_argument('-a',
                                     '--host',
                                     metavar='hostname',
                                     type=str,
                                     help=getMessage("en", "host-argument"))
        self._argparser.add_argument('-n',
                                     '--name',
                                     metavar='username',
                                     type=str,
                                     help=getMessage("en", "name-argument"))
        self._argparser.add_argument('-d',
                                     '--debug',
                                     action='store_true',
                                     help=getMessage("en", "debug-argument"))
        self._argparser.add_argument('-g',
                                     '--force-gui-prompt',
                                     action='store_true',
                                     help=getMessage(
                                         "en", "force-gui-prompt-argument"))
        self._argparser.add_argument('--no-store',
                                     action='store_true',
                                     help=getMessage("en",
                                                     "no-store-argument"))
        self._argparser.add_argument('-r',
                                     '--room',
                                     metavar='room',
                                     type=str,
                                     nargs='?',
                                     help=getMessage("en", "room-argument"))
        self._argparser.add_argument('-p',
                                     '--password',
                                     metavar='password',
                                     type=str,
                                     nargs='?',
                                     help=getMessage("en",
                                                     "password-argument"))
        self._argparser.add_argument('--player-path',
                                     metavar='path',
                                     type=str,
                                     help=getMessage("en",
                                                     "player-path-argument"))
        self._argparser.add_argument('file',
                                     metavar='file',
                                     type=str,
                                     nargs='?',
                                     help=getMessage("en", "file-argument"))
        self._argparser.add_argument('--clear-gui-data',
                                     action='store_true',
                                     help=getMessage(
                                         "en", "clear-gui-data-argument"))
        self._argparser.add_argument('_args',
                                     metavar='options',
                                     type=str,
                                     nargs='*',
                                     help=getMessage("en", "args-argument"))

        self._playerFactory = PlayerFactory()

    def _validateArguments(self):
        for key in self._boolean:
            if (self._config[key] == "True"):
                self._config[key] = True
            elif (self._config[key] == "False"):
                self._config[key] = False
        for key in self._required:
            if (key == "playerPath"):
                player = self._playerFactory.getPlayerByPath(
                    self._config["playerPath"])
                if (player):
                    self._config["playerClass"] = player
                else:
                    raise InvalidConfigValue("Player path is not set properly")
                if player.__name__ in ['MpvPlayer', 'MplayerPlayer']:
                    if not self._config['file']:
                        raise InvalidConfigValue(
                            "File must be selected before starting your player"
                        )
            elif (key == "host"):
                self._config["host"], self._config[
                    "port"] = self._splitPortAndHost(self._config["host"])
                hostNotValid = (self._config["host"] == ""
                                or self._config["host"] is None)
                portNotValid = (self._config["port"] == ""
                                or self._config["port"] is None)
                if (hostNotValid or portNotValid):
                    raise InvalidConfigValue("Hostname can't be empty")
            elif (self._config[key] == "" or self._config[key] is None):
                raise InvalidConfigValue("{} can't be empty".format(
                    key.capitalize()))

    def _overrideConfigWithArgs(self, args):
        for key, val in vars(args).items():
            if (val):
                if (key == "force_gui_prompt"):
                    key = "forceGuiPrompt"
                if (key == "no_store"):
                    key = "noStore"
                if (key == "player_path"):
                    key = "playerPath"
                if (key == "_args"):
                    key = "playerArgs"
                if (key == "no_gui"):
                    key = "noGui"
                if (key == "clear_gui_data"):
                    key = "clearGUIData"
                self._config[key] = val

    def _splitPortAndHost(self, host):
        port = constants.DEFAULT_PORT if not self._config[
            "port"] else self._config["port"]
        if (host):
            if ':' in host:
                host, port = host.split(':', 1)
        return host, int(port)

    def _checkForPortableFile(self):
        path = utils.findWorkingDir()
        for name in constants.CONFIG_NAMES:
            if (os.path.isfile(os.path.join(path, name))):
                return os.path.join(path, name)

    def _getConfigurationFilePath(self):
        configFile = self._checkForPortableFile()
        if not configFile:
            for name in constants.CONFIG_NAMES:
                if (configFile and os.path.isfile(configFile)):
                    break
                if (os.name <> 'nt'):
                    configFile = os.path.join(os.getenv('HOME', '.'), name)
                else:
                    configFile = os.path.join(os.getenv('APPDATA', '.'), name)
            if (configFile and not os.path.isfile(configFile)):
                if (os.name <> 'nt'):
                    configFile = os.path.join(
                        os.getenv('HOME', '.'),
                        constants.DEFAULT_CONFIG_NAME_LINUX)
                else:
                    configFile = os.path.join(
                        os.getenv('APPDATA', '.'),
                        constants.DEFAULT_CONFIG_NAME_WINDOWS)

        return configFile

    def _parseConfigFile(self, iniPath, createConfig=True):
        parser = SafeConfigParserUnicode()
        if (not os.path.isfile(iniPath)):
            if (createConfig):
                open(iniPath, 'w').close()
            else:
                return
        parser.readfp(codecs.open(iniPath, "r", "utf_8_sig"))
        for section, options in self._iniStructure.items():
            if (parser.has_section(section)):
                for option in options:
                    if (parser.has_option(section, option)):
                        self._config[option] = parser.get(section, option)

    def _checkConfig(self):
        try:
            self._validateArguments()
        except InvalidConfigValue as e:
            try:
                for key, value in self._promptForMissingArguments(
                        e.message).items():
                    self._config[key] = value
                self._checkConfig()
            except:
                sys.exit()

    def _promptForMissingArguments(self, error=None):
        if (self._config['noGui']):
            print getMessage("en", "missing-arguments-error")
            sys.exit()
        elif (GuiConfiguration):
            gc = GuiConfiguration(self._config, error=error)
            gc.setAvailablePaths(self._playerFactory.getAvailablePlayerPaths())
            gc.run()
            return gc.getProcessedConfiguration()

    def __wasOptionChanged(self, parser, section, option):
        if (parser.has_option(section, option)):
            if (parser.get(section, option) != unicode(self._config[option])):
                return True
        else:
            return True

    def _saveConfig(self, iniPath):
        changed = False
        if (self._config['noStore']):
            return
        parser = SafeConfigParserUnicode()
        parser.readfp(codecs.open(iniPath, "r", "utf_8_sig"))
        for section, options in self._iniStructure.items():
            if (not parser.has_section(section)):
                parser.add_section(section)
                changed = True
            for option in options:
                if (self.__wasOptionChanged(parser, section, option)):
                    changed = True
                parser.set(section, option, unicode(self._config[option]))
        if (changed):
            parser.write(codecs.open(iniPath, "wb", "utf_8_sig"))

    def _forceGuiPrompt(self):
        try:
            self._validateArguments()
        except InvalidConfigValue:
            pass
        try:
            if (self._config['noGui'] == False):
                for key, value in self._promptForMissingArguments().items():
                    self._config[key] = value
        except GuiConfiguration.WindowClosed:
            sys.exit()

    def __getRelativeConfigLocations(self):
        locations = []
        path = os.path.dirname(os.path.realpath(self._config['file']))
        locations.append(path)
        while path != os.path.dirname(path):
            path = os.path.dirname(path)
            locations.append(path)
        locations.reverse()
        return locations

    def _loadRelativeConfiguration(self):
        locations = self.__getRelativeConfigLocations()
        for location in locations:
            for name in constants.CONFIG_NAMES:
                path = location + os.path.sep + name
                self._parseConfigFile(path, createConfig=False)
                self._checkConfig()

    def getConfiguration(self):
        iniPath = self._getConfigurationFilePath()
        self._parseConfigFile(iniPath)
        args = self._argparser.parse_args()
        self._overrideConfigWithArgs(args)
        #Arguments not validated yet - booleans are still text values
        if (self._config['forceGuiPrompt'] == "True"
                or not self._config['file']):
            self._forceGuiPrompt()
        self._checkConfig()
        self._saveConfig(iniPath)
        if (self._config['file']):
            self._loadRelativeConfiguration()
        if (not self._config['noGui']):
            from syncplay.vendor import qt4reactor
            if QCoreApplication.instance() is None:
                self.app = QtGui.QApplication(sys.argv)
            qt4reactor.install()
        return self._config
예제 #16
0
class ConfigurationGetter(object):
    def __init__(self):
        self._config = {
                        "host": None,
                        "port": constants.DEFAULT_PORT,
                        "name": None,
                        "debug": False,
                        "forceGuiPrompt": False,
                        "noGui": False,
                        "noStore": False,
                        "room": "",
                        "password": None,
                        "playerPath": None,
                        "file": None,
                        "playerArgs": [],
                        "playerClass": None,
						"slowOnDesync": True,
                        "malUsername": "",
                        "malPassword": ""
                        }
        
        #
        #Custom validation in self._validateArguments
        #
        self._required = [
                          "host",
                          "port",
                          "name",
                          "playerPath",
                          "playerClass",
                         ]
        
        self._boolean = [
                         "debug",
                         "forceGuiPrompt",
                         "noGui",
                         "noStore",
                         "slowOnDesync"
                        ]

        self._iniStructure = {
                        "server_data": ["host", "port", "password"],
                        "client_settings": ["name", "room", "playerPath", "slowOnDesync", "forceGuiPrompt"],
                        "mal": ["malPassword", "malUsername"]
                        }

        #
        #Watch out for the method self._overrideConfigWithArgs when you're adding custom multi-word command line arguments
        #
        self._argparser = argparse.ArgumentParser(description=getMessage("en", "argument-description"),
                                         epilog=getMessage("en", "argument-epilog"))
        self._argparser.add_argument('--no-gui', action='store_true', help=getMessage("en", "nogui-argument"))
        self._argparser.add_argument('-a', '--host', metavar='hostname', type=str, help=getMessage("en", "host-argument"))
        self._argparser.add_argument('-n', '--name', metavar='username', type=str, help=getMessage("en", "name-argument"))
        self._argparser.add_argument('-d', '--debug', action='store_true', help=getMessage("en", "debug-argument"))
        self._argparser.add_argument('-g', '--force-gui-prompt', action='store_true', help=getMessage("en", "force-gui-prompt-argument"))
        self._argparser.add_argument('--no-store', action='store_true', help=getMessage("en", "no-store-argument"))
        self._argparser.add_argument('-r', '--room', metavar='room', type=str, nargs='?', help=getMessage("en", "room-argument"))
        self._argparser.add_argument('-p', '--password', metavar='password', type=str, nargs='?', help=getMessage("en", "password-argument"))
        self._argparser.add_argument('--player-path', metavar='path', type=str, help=getMessage("en", "player-path-argument"))
        self._argparser.add_argument('file', metavar='file', type=str, nargs='?', help=getMessage("en", "file-argument"))
        self._argparser.add_argument('_args', metavar='options', type=str, nargs='*', help=getMessage("en", "args-argument"))
  
        self._playerFactory = PlayerFactory()
        
    def _validateArguments(self):
        for key in self._boolean:
            if(self._config[key] == "True"):
                self._config[key] = True
            elif(self._config[key] == "False"):
                self._config[key] = False
        for key in self._required:
            if(key == "playerPath"):
                player = self._playerFactory.getPlayerByPath(self._config["playerPath"])
                if(player):
                    self._config["playerClass"] = player
                else:
                    raise InvalidConfigValue("Player path is not set properly")
            elif(key == "host"):
                self._config["host"], self._config["port"] = self._splitPortAndHost(self._config["host"])
                hostNotValid = (self._config["host"] == "" or self._config["host"] is None)
                portNotValid = (self._config["port"] == "" or self._config["port"] is None)
                if(hostNotValid or portNotValid):
                    raise InvalidConfigValue("Hostname can't be empty")
            elif(self._config[key] == "" or self._config[key] is None):
                raise InvalidConfigValue("{} can't be empty".format(key))

    def _overrideConfigWithArgs(self, args):
        for key, val in vars(args).items():
            if(val):
                if(key == "force_gui_prompt"):
                    key = "forceGuiPrompt"
                if(key == "no_store"):
                    key = "noStore"
                if(key == "player_path"):
                    key = "playerPath"
                if(key == "_args"):
                    key = "playerArgs"
                if(key == "no_gui"):
                    key = "noGui"
                self._config[key] = val
            
    def _splitPortAndHost(self, host):
        port = constants.DEFAULT_PORT if not self._config["port"] else self._config["port"]
        if(host):
            if ':' in host:
                host, port = host.split(':', 1)
        return host, int(port)
        
    def _checkForPortableFile(self):
        path = utils.findWorkingDir()
        if(os.path.isfile(os.path.join(path, constants.DEFAULT_CONFIG_NAME))):
            return os.path.join(path, constants.DEFAULT_CONFIG_NAME) 
        
    def _getConfigurationFilePath(self):
        configFile = self._checkForPortableFile()
        if(not configFile):
            if(os.name <> 'nt'):
                configFile = os.path.join(os.getenv('HOME', '.'), constants.DEFAULT_CONFIG_NAME)
            else:
                configFile = os.path.join(os.getenv('APPDATA', '.'), constants.DEFAULT_CONFIG_NAME)
        return configFile

    def _parseConfigFile(self, iniPath, createConfig = True):
        parser = SafeConfigParser()
        if(not os.path.isfile(iniPath)):
            if(createConfig):
                open(iniPath, 'w').close()
            else:
                return
        parser.readfp(codecs.open(iniPath, "r", "utf_8_sig"))
        for section, options in self._iniStructure.items():
            if(parser.has_section(section)):
                for option in options:
                    if(parser.has_option(section, option)):
                        self._config[option] = parser.get(section, option)
        
    def _checkConfig(self):
        try:
            self._validateArguments()
        except InvalidConfigValue:
            try:
                for key, value in self._promptForMissingArguments().items():
                    self._config[key] = value
                self._checkConfig()
            except:
                sys.exit()

    def _promptForMissingArguments(self):
        if(self._config['noGui']):
            print getMessage("en", "missing-arguments-error")
            sys.exit()
        elif(GuiConfiguration):
            gc = GuiConfiguration(self._config)
            gc.setAvailablePaths(self._playerFactory.getAvailablePlayerPaths())
            gc.run()
            return gc.getProcessedConfiguration()

    def __wasOptionChanged(self, parser, section, option):
        if (parser.has_option(section, option)):
            if (parser.get(section, option) != str(self._config[option])):
                return True
        else:
            return True

    def _saveConfig(self, iniPath):
        changed = False
        if(self._config['noStore']):
            return
        parser = SafeConfigParser()
        parser.readfp(codecs.open(iniPath, "r", "utf_8_sig"))
        for section, options in self._iniStructure.items():
            if(not parser.has_section(section)):
                parser.add_section(section)
                changed = True
            for option in options:
                if(self.__wasOptionChanged(parser, section, option)):
                    changed = True
                parser.set(section, option, str(self._config[option]))
        if(changed):
            parser.write(codecs.open(iniPath, "wb", "utf_8_sig"))
        

    def _forceGuiPrompt(self):
        try:
            self._validateArguments()
        except InvalidConfigValue:
            pass
        try:
            for key, value in self._promptForMissingArguments().items():
                self._config[key] = value
        except:
            sys.exit()


    def __getRelativeConfigLocations(self):
        locations = []
        path = os.path.dirname(os.path.realpath(self._config['file']))
        locations.append(path)
        while path != os.path.dirname(path):
            path = os.path.dirname(path)
            locations.append(path)
        locations.reverse()
        return locations

    def _loadRelativeConfiguration(self):
        locations = self.__getRelativeConfigLocations()
        for location in locations:
            path = location + os.path.sep + constants.DEFAULT_CONFIG_NAME
            self._parseConfigFile(path, createConfig = False)
            self._checkConfig()

    def getConfiguration(self):
        iniPath = self._getConfigurationFilePath()
        self._parseConfigFile(iniPath)
        args = self._argparser.parse_args()
        self._overrideConfigWithArgs(args)
        #Arguments not validated yet - booleans are still text values
        if(self._config['forceGuiPrompt'] == "True" or not self._config['file']): 
            self._forceGuiPrompt()
        self._checkConfig()
        self._saveConfig(iniPath)
        if(self._config['file']):
            self._loadRelativeConfiguration()
        return self._config
예제 #17
0
class ConfigurationGetter(object):
    def __init__(self):
        self._config = {
            "host": None,
            "port": constants.DEFAULT_PORT,
            "name": None,
            "debug": False,
            "forceGuiPrompt": True,
            "noGui": False,
            "noStore": False,
            "room": "",
            "password": None,
            "playerPath": None,
            "perPlayerArguments": None,
            "mediaSearchDirectories": None,
            "file": None,
            "playerArgs": [],
            "playerClass": None,
            "slowdownThreshold": constants.DEFAULT_SLOWDOWN_KICKIN_THRESHOLD,
            "rewindThreshold": constants.DEFAULT_REWIND_THRESHOLD,
            "fastforwardThreshold": constants.DEFAULT_FASTFORWARD_THRESHOLD,
            "rewindOnDesync": True,
            "slowOnDesync": True,
            "fastforwardOnDesync": True,
            "dontSlowDownWithMe": False,
            "filenamePrivacyMode": constants.PRIVACY_SENDRAW_MODE,
            "filesizePrivacyMode": constants.PRIVACY_SENDRAW_MODE,
            "pauseOnLeave": False,
            "readyAtStart": False,
            "unpauseAction": constants.UNPAUSE_IFOTHERSREADY_MODE,
            "autoplayInitialState": None,
            "autoplayMinUsers": -1,
            "clearGUIData": False,
            "language": "",
            "checkForUpdatesAutomatically": None,
            "lastCheckedForUpdates": "",
            "resetConfig": False,
            "showOSD": True,
            "showOSDWarnings": True,
            "showSlowdownOSD": True,
            "showDifferentRoomOSD": False,
            "showSameRoomOSD": True,
            "showNonControllerOSD": False,
            "showContactInfo": True,
            "showDurationNotification": True
        }

        self._defaultConfig = self._config.copy()

        #
        # Custom validation in self._validateArguments
        #
        self._required = [
            "host",
            "port",
            "room",
            "playerPath",
            "playerClass",
        ]

        self._boolean = [
            "debug", "forceGuiPrompt", "noGui", "noStore",
            "dontSlowDownWithMe", "pauseOnLeave", "readyAtStart",
            "clearGUIData", "rewindOnDesync", "slowOnDesync",
            "fastforwardOnDesync", "pauseOnLeave", "clearGUIData",
            "resetConfig", "showOSD", "showOSDWarnings", "showSlowdownOSD",
            "showDifferentRoomOSD", "showSameRoomOSD", "showNonControllerOSD",
            "showDurationNotification"
        ]
        self._tristate = [
            "checkForUpdatesAutomatically",
            "autoplayInitialState",
        ]

        self._serialised = [
            "perPlayerArguments",
            "mediaSearchDirectories",
        ]

        self._numeric = [
            "slowdownThreshold",
            "rewindThreshold",
            "fastforwardThreshold",
            "autoplayMinUsers",
        ]

        self._iniStructure = {
            "server_data": ["host", "port", "password"],
            "client_settings": [
                "name", "room", "playerPath", "perPlayerArguments",
                "slowdownThreshold", "rewindThreshold", "fastforwardThreshold",
                "slowOnDesync", "rewindOnDesync", "fastforwardOnDesync",
                "dontSlowDownWithMe", "forceGuiPrompt", "filenamePrivacyMode",
                "filesizePrivacyMode", "unpauseAction", "pauseOnLeave",
                "readyAtStart", "autoplayMinUsers", "autoplayInitialState",
                "mediaSearchDirectories"
            ],
            "gui": [
                "showOSD", "showOSDWarnings", "showSlowdownOSD",
                "showDifferentRoomOSD", "showSameRoomOSD",
                "showNonControllerOSD", "showDurationNotification"
            ],
            "general": [
                "language", "checkForUpdatesAutomatically",
                "lastCheckedForUpdates"
            ]
        }

        self._playerFactory = PlayerFactory()

    def _validateArguments(self):
        if self._config['resetConfig']:
            language = self._config['language']
            checkForUpdatesAutomatically = self._config[
                'checkForUpdatesAutomatically']
            self._config = self._defaultConfig
            self._config['language'] = language
            self._config[
                'checkForUpdatesAutomatically'] = checkForUpdatesAutomatically
            raise InvalidConfigValue("*" +
                                     getMessage("config-cleared-notification"))

        if not isValidLanguage(self._config['language']):
            self._config['language'] = ""

        def _isPortValid(varToTest):
            try:
                if varToTest == "" or varToTest is None:
                    return False
                if str(varToTest).isdigit() == False:
                    return False
                varToTest = int(varToTest)
                if varToTest > 65535 or varToTest < 1:
                    return False
                return True
            except:
                return False

        for key in self._boolean:
            if self._config[key] == "True":
                self._config[key] = True
            elif self._config[key] == "False":
                self._config[key] = False

        for key in self._serialised:
            if self._config[key] is None or self._config[key] == "":
                self._config[key] = {}
            elif isinstance(self._config[key], (str, unicode)):
                self._config[key] = ast.literal_eval(self._config[key])

        for key in self._tristate:
            if self._config[key] == "True":
                self._config[key] = True
            elif self._config[key] == "False":
                self._config[key] = False
            elif self._config[key] == "None":
                self._config[key] = None

        for key in self._numeric:
            self._config[key] = float(self._config[key])

        for key in self._required:
            if key == "playerPath":
                player = None
                if self._config["playerPath"]:
                    player = self._playerFactory.getPlayerByPath(
                        self._config["playerPath"])
                if player:
                    self._config["playerClass"] = player
                else:
                    raise InvalidConfigValue(
                        getMessage("player-path-config-error"))
                playerPathErrors = player.getPlayerPathErrors(
                    self._config["playerPath"],
                    self._config['file'] if self._config['file'] else None)
                if playerPathErrors:
                    raise InvalidConfigValue(playerPathErrors)
            elif key == "host":
                self._config["host"], self._config[
                    "port"] = self._splitPortAndHost(self._config["host"])
                hostNotValid = (self._config["host"] == ""
                                or self._config["host"] is None)
                portNotValid = (_isPortValid(self._config["port"]) == False)
                if hostNotValid:
                    raise InvalidConfigValue(
                        getMessage("no-hostname-config-error"))
                elif portNotValid:
                    raise InvalidConfigValue(
                        getMessage("invalid-port-config-error"))
            elif self._config[key] == "" or self._config[key] is None:
                raise InvalidConfigValue(
                    getMessage("empty-value-config-error").format(
                        key.capitalize()))

    def _overrideConfigWithArgs(self, args):
        for key, val in vars(args).items():
            if val:
                if key == "force_gui_prompt":
                    key = "forceGuiPrompt"
                if key == "no_store":
                    key = "noStore"
                if key == "player_path":
                    key = "playerPath"
                if key == "_args":
                    key = "playerArgs"
                if key == "no_gui":
                    key = "noGui"
                if key == "clear_gui_data":
                    key = "clearGUIData"
                self._config[key] = val

    def _splitPortAndHost(self, host):
        port = constants.DEFAULT_PORT if not self._config[
            "port"] else self._config["port"]
        if host:
            if ':' in host:
                host, port = host.split(':', 1)
                try:
                    port = int(port)
                except ValueError:
                    try:
                        port = port.encode('ascii', 'ignore')
                    except:
                        port = ""
        return host, port

    def _checkForPortableFile(self):
        path = utils.findWorkingDir()
        for name in constants.CONFIG_NAMES:
            if os.path.isfile(os.path.join(path, name)):
                return os.path.join(path, name)

    def _getConfigurationFilePath(self):
        configFile = self._checkForPortableFile()
        if not configFile:
            for name in constants.CONFIG_NAMES:
                if configFile and os.path.isfile(configFile):
                    break
                if os.name <> 'nt':
                    configFile = os.path.join(os.getenv('HOME', '.'), name)
                else:
                    configFile = os.path.join(os.getenv('APPDATA', '.'), name)
            if configFile and not os.path.isfile(configFile):
                if os.name <> 'nt':
                    configFile = os.path.join(
                        os.getenv('HOME', '.'),
                        constants.DEFAULT_CONFIG_NAME_LINUX)
                else:
                    configFile = os.path.join(
                        os.getenv('APPDATA', '.'),
                        constants.DEFAULT_CONFIG_NAME_WINDOWS)

        return configFile

    def _parseConfigFile(self, iniPath, createConfig=True):
        parser = SafeConfigParserUnicode()
        if not os.path.isfile(iniPath):
            if createConfig:
                open(iniPath, 'w').close()
            else:
                return
        parser.readfp(codecs.open(iniPath, "r", "utf_8_sig"))
        for section, options in self._iniStructure.items():
            if parser.has_section(section):
                for option in options:
                    if parser.has_option(section, option):
                        self._config[option] = parser.get(section, option)

    def _checkConfig(self):
        try:
            self._validateArguments()
        except InvalidConfigValue as e:
            try:
                for key, value in self._promptForMissingArguments(
                        e.message).items():
                    self._config[key] = value
                self._checkConfig()
            except:
                sys.exit()

    def _promptForMissingArguments(self, error=None):
        if self._config['noGui'] or not GuiConfiguration:
            if error:
                print "{}!".format(error)
            print getMessage("missing-arguments-error")
            sys.exit()
        elif GuiConfiguration:
            gc = GuiConfiguration(self._config, error=error)
            gc.setAvailablePaths(self._playerFactory.getAvailablePlayerPaths())
            gc.run()
            return gc.getProcessedConfiguration()

    def __wasOptionChanged(self, parser, section, option):
        if parser.has_option(section, option):
            if parser.get(section, option) != unicode(self._config[option]):
                return True
        else:
            return True

    def _saveConfig(self, iniPath):
        changed = False
        if self._config['noStore']:
            return
        parser = SafeConfigParserUnicode()
        parser.readfp(codecs.open(iniPath, "r", "utf_8_sig"))
        for section, options in self._iniStructure.items():
            if not parser.has_section(section):
                parser.add_section(section)
                changed = True
            for option in options:
                if self.__wasOptionChanged(parser, section, option):
                    changed = True
                parser.set(section, option,
                           unicode(self._config[option]).replace('%', '%%'))
        if changed:
            parser.write(codecs.open(iniPath, "wb", "utf_8_sig"))

    def _forceGuiPrompt(self):
        if GuiConfiguration:
            try:
                self._validateArguments()
            except InvalidConfigValue:
                pass

            try:
                if self._config['noGui'] == False:
                    for key, value in self._promptForMissingArguments().items(
                    ):
                        self._config[key] = value
            except GuiConfiguration.WindowClosed:
                sys.exit()
        else:
            try:
                self._validateArguments()
            except InvalidConfigValue:
                self._promptForMissingArguments()
                sys.exit()

    def __getRelativeConfigLocations(self):
        locations = []
        path = os.path.dirname(os.path.realpath(self._config['file']))
        locations.append(path)
        while path != os.path.dirname(path):
            path = os.path.dirname(path)
            locations.append(path)
        locations.reverse()
        return locations

    def _loadRelativeConfiguration(self):
        locations = self.__getRelativeConfigLocations()
        loadedPaths = []
        for location in locations:
            for name in constants.CONFIG_NAMES:
                path = location + os.path.sep + name
                if os.path.isfile(path) and (
                        os.name == 'nt' or path != os.path.join(
                            os.getenv('HOME', '.'),
                            constants.DEFAULT_CONFIG_NAME_LINUX)):
                    loadedPaths.append("'" + os.path.normpath(path) + "'")
                    self._parseConfigFile(path, createConfig=False)
                    self._checkConfig()
        return loadedPaths

    def getConfiguration(self):
        iniPath = self._getConfigurationFilePath()
        self._parseConfigFile(iniPath)
        #
        # Watch out for the method self._overrideConfigWithArgs when you're adding custom multi-word command line arguments
        #
        if self._config['language']:
            setLanguage(self._config['language'])
        self._argparser = argparse.ArgumentParser(
            description=getMessage("argument-description"),
            epilog=getMessage("argument-epilog"))
        self._argparser.add_argument('--no-gui',
                                     action='store_true',
                                     help=getMessage("nogui-argument"))
        self._argparser.add_argument('-a',
                                     '--host',
                                     metavar='hostname',
                                     type=str,
                                     help=getMessage("host-argument"))
        self._argparser.add_argument('-n',
                                     '--name',
                                     metavar='username',
                                     type=str,
                                     help=getMessage("name-argument"))
        self._argparser.add_argument('-d',
                                     '--debug',
                                     action='store_true',
                                     help=getMessage("debug-argument"))
        self._argparser.add_argument(
            '-g',
            '--force-gui-prompt',
            action='store_true',
            help=getMessage("force-gui-prompt-argument"))
        self._argparser.add_argument('--no-store',
                                     action='store_true',
                                     help=getMessage("no-store-argument"))
        self._argparser.add_argument('-r',
                                     '--room',
                                     metavar='room',
                                     type=str,
                                     nargs='?',
                                     help=getMessage("room-argument"))
        self._argparser.add_argument('-p',
                                     '--password',
                                     metavar='password',
                                     type=str,
                                     nargs='?',
                                     help=getMessage("password-argument"))
        self._argparser.add_argument('--player-path',
                                     metavar='path',
                                     type=str,
                                     help=getMessage("player-path-argument"))
        self._argparser.add_argument('--language',
                                     metavar='language',
                                     type=str,
                                     help=getMessage("language-argument"))
        self._argparser.add_argument('file',
                                     metavar='file',
                                     type=lambda s: unicode(s, 'utf8'),
                                     nargs='?',
                                     help=getMessage("file-argument"))
        self._argparser.add_argument(
            '--clear-gui-data',
            action='store_true',
            help=getMessage("clear-gui-data-argument"))
        self._argparser.add_argument('-v',
                                     '--version',
                                     action='store_true',
                                     help=getMessage("version-argument"))
        self._argparser.add_argument('_args',
                                     metavar='options',
                                     type=str,
                                     nargs='*',
                                     help=getMessage("args-argument"))
        args = self._argparser.parse_args()
        if args.version:
            print getMessage("version-message").format(version, milestone)
            sys.exit()
        self._overrideConfigWithArgs(args)
        if self._config['file'] and self._config['file'][:2] == "--":
            self._config['playerArgs'].insert(0, self._config['file'])
            self._config['file'] = None
        # Arguments not validated yet - booleans are still text values
        if self._config['language']:
            setLanguage(self._config['language'])
        if (self._config['forceGuiPrompt'] == "True"
                or not self._config['file']
            ) and GuiConfiguration and not self._config['noGui']:
            self._forceGuiPrompt()
        self._checkConfig()
        self._saveConfig(iniPath)
        if self._config['file']:
            self._config[
                'loadedRelativePaths'] = self._loadRelativeConfiguration()
        if self._config['language']:
            setLanguage(self._config['language'])
        if not GuiConfiguration:
            self._config['noGui'] = True
        if not self._config['noGui']:
            from syncplay.vendor import qt4reactor
            if QCoreApplication.instance() is None:
                self.app = QtGui.QApplication(sys.argv)
            qt4reactor.install()
        return self._config