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()
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)
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()))
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
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()
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
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()
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()
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
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()
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
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()
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
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()
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
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
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