diff --git a/syncplay/ui/ConfigurationGetter.py b/syncplay/ui/ConfigurationGetter.py index f7d311f..03897ee 100755 --- a/syncplay/ui/ConfigurationGetter.py +++ b/syncplay/ui/ConfigurationGetter.py @@ -1,95 +1,99 @@ -from configparser import SafeConfigParser, DEFAULTSECT + import argparse +import ast +import codecs +import re import os import sys -import ast +from configparser import SafeConfigParser, DEFAULTSECT + from syncplay import constants, utils, version, milestone from syncplay.messages import getMessage, setLanguage, isValidLanguage from syncplay.players.playerFactory import PlayerFactory from syncplay.utils import isMacOS -import codecs -import re + class InvalidConfigValue(Exception): def __init__(self, message): Exception.__init__(self, message) + 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" : [] - } + "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() @@ -97,47 +101,47 @@ class ConfigurationGetter(object): # Custom validation in self._validateArguments # self._required = [ - "host", - "port", - "room", - "playerPath", - "playerClass", - ] + "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" - ] + "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", @@ -174,37 +178,40 @@ class ConfigurationGetter(object): ] 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"] - } + "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() @@ -215,7 +222,7 @@ class ConfigurationGetter(object): self._config = self._defaultConfig self._config['language'] = language self._config['checkForUpdatesAutomatically'] = checkForUpdatesAutomatically - raise InvalidConfigValue("*"+getMessage("config-cleared-notification")) + raise InvalidConfigValue("*" + getMessage("config-cleared-notification")) if not isValidLanguage(self._config['language']): self._config['language'] = "" @@ -224,7 +231,7 @@ class ConfigurationGetter(object): try: if varToTest == "" or varToTest is None: return False - if str(varToTest).isdigit() == False: + if not str(varToTest).isdigit(): return False varToTest = int(varToTest) if varToTest > 65535 or varToTest < 1: @@ -269,13 +276,14 @@ class ConfigurationGetter(object): 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) + 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) + portNotValid = (not _isPortValid(self._config["port"])) if hostNotValid: raise InvalidConfigValue(getMessage("no-hostname-config-error")) elif portNotValid: @@ -325,12 +333,12 @@ class ConfigurationGetter(object): if configFile: return configFile for name in constants.CONFIG_NAMES: - configFile = self._expandConfigPath(name, xdg = False) + configFile = self._expandConfigPath(name, xdg=False) if os.path.isfile(configFile): return configFile return self._expandConfigPath() - def _expandConfigPath(self, name = None, xdg = True): + def _expandConfigPath(self, name=None, xdg=True): if os.name != 'nt': if xdg: prefix = self._getXdgConfigHome() @@ -408,7 +416,6 @@ class ConfigurationGetter(object): if changed: parser.write(codecs.open(iniPath, "wb", "utf_8_sig")) - def _forceGuiPrompt(self): from syncplay.ui.GuiConfiguration import GuiConfiguration try: @@ -452,8 +459,9 @@ class ConfigurationGetter(object): # if self._config['language']: setLanguage(self._config['language']) - self._argparser = argparse.ArgumentParser(description=getMessage("argument-description"), - epilog=getMessage("argument-epilog")) + 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")) @@ -481,7 +489,7 @@ class ConfigurationGetter(object): if not (IsPySide2 or IsPySide): raise ImportError if QCoreApplication.instance() is None: - self.app = QtWidgets.QApplication(sys.argv) + self.app = QtWidgets.QApplication(sys.argv) qt5reactor.install() if isMacOS(): import appnope @@ -514,6 +522,7 @@ class ConfigurationGetter(object): self._saveConfig(path) self._config = backup + class SafeConfigParserUnicode(SafeConfigParser): def write(self, fp): """Write an .ini-format representation of the configuration state.""" diff --git a/syncplay/ui/GuiConfiguration.py b/syncplay/ui/GuiConfiguration.py index ab24c50..741810a 100755 --- a/syncplay/ui/GuiConfiguration.py +++ b/syncplay/ui/GuiConfiguration.py @@ -1,19 +1,24 @@ + +import os +import sys +import threading +from datetime import datetime + +from syncplay import constants +from syncplay import utils +from syncplay.messages import getMessage, getLanguages, setLanguage, getInitialLanguage +from syncplay.players.playerFactory import PlayerFactory +from syncplay.utils import isBSD, isLinux, isMacOS, isWindows +from syncplay.utils import resourcespath, posixresourcespath + from syncplay.vendor.Qt import QtCore, QtWidgets, QtGui, __binding__, IsPySide, IsPySide2 from syncplay.vendor.Qt.QtCore import Qt, QSettings, QCoreApplication, QSize, QPoint, QUrl, QLine, QEventLoop, Signal from syncplay.vendor.Qt.QtWidgets import QApplication, QLineEdit, QLabel, QCheckBox, QButtonGroup, QRadioButton, QDoubleSpinBox, QPlainTextEdit from syncplay.vendor.Qt.QtGui import QCursor, QIcon, QImage, QDesktopServices if IsPySide2: from PySide2.QtCore import QStandardPaths -from syncplay.players.playerFactory import PlayerFactory -from datetime import datetime -from syncplay import utils -import os -import sys -import threading -from syncplay.messages import getMessage, getLanguages, setLanguage, getInitialLanguage -from syncplay import constants -from syncplay.utils import isBSD, isLinux, isMacOS, isWindows -from syncplay.utils import resourcespath, posixresourcespath + + class GuiConfiguration: def __init__(self, config, error=None, defaultConfig=None): self.defaultConfig = defaultConfig @@ -77,13 +82,15 @@ class ConfigDialog(QtWidgets.QDialog): pressedclosebutton = True moreToggling = False - + closed = Signal() def automaticUpdatePromptCheck(self): if self.automaticupdatesCheckbox.checkState() == Qt.PartiallyChecked: - reply = QtWidgets.QMessageBox.question(self, "Syncplay", - getMessage("promptforupdate-label"), QtWidgets.QMessageBox.StandardButton.Yes | QtWidgets.QMessageBox.StandardButton.No) + reply = QtWidgets.QMessageBox.question( + self, "Syncplay", + getMessage("promptforupdate-label"), + QtWidgets.QMessageBox.StandardButton.Yes | QtWidgets.QMessageBox.StandardButton.No) if reply == QtWidgets.QMessageBox.Yes: self.automaticupdatesCheckbox.setChecked(True) else: @@ -91,7 +98,7 @@ class ConfigDialog(QtWidgets.QDialog): def moreToggled(self): self.setSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) - if self.moreToggling == False: + if not self.moreToggling: self.moreToggling = True if self.showmoreCheckbox.isChecked(): @@ -123,7 +130,7 @@ class ConfigDialog(QtWidgets.QDialog): self.mediabrowseButton.show() self.saveMoreState(False) self.stackedLayout.setCurrentIndex(0) - newHeight = self.connectionSettingsGroup.minimumSizeHint().height()+self.mediaplayerSettingsGroup.minimumSizeHint().height()+self.bottomButtonFrame.minimumSizeHint().height()+3 + newHeight = self.connectionSettingsGroup.minimumSizeHint().height() + self.mediaplayerSettingsGroup.minimumSizeHint().height() + self.bottomButtonFrame.minimumSizeHint().height() + 3 if self.error: newHeight += self.errorLabel.height()+3 self.stackedFrame.setFixedHeight(newHeight) @@ -154,7 +161,7 @@ class ConfigDialog(QtWidgets.QDialog): settings.endGroup() foundpath = "" - if playerpath != None and playerpath != "": + if playerpath is not None and playerpath != "": if utils.isURL(playerpath): foundpath = playerpath self.executablepathCombobox.addItem(foundpath) @@ -162,7 +169,7 @@ class ConfigDialog(QtWidgets.QDialog): else: if not os.path.isfile(playerpath): expandedpath = PlayerFactory().getExpandedPlayerPathByPath(playerpath) - if expandedpath != None and os.path.isfile(expandedpath): + if expandedpath is not None and os.path.isfile(expandedpath): playerpath = expandedpath if os.path.isfile(playerpath): @@ -226,7 +233,7 @@ class ConfigDialog(QtWidgets.QDialog): if currentplayerpath: NewPlayerArgs = self.playerargsTextbox.text().split(" ") if self.playerargsTextbox.text() else "" - self.perPlayerArgs[self.executablepathCombobox.currentText()]=NewPlayerArgs + self.perPlayerArgs[self.executablepathCombobox.currentText()] = NewPlayerArgs def languageChanged(self): setLanguage(str(self.languageCombobox.itemData(self.languageCombobox.currentIndex()))) @@ -252,10 +259,11 @@ class ConfigDialog(QtWidgets.QDialog): elif isBSD(): defaultdirectory = "/usr/local/bin" - fileName, filtr = QtWidgets.QFileDialog.getOpenFileName(self, - "Browse for media player executable", - defaultdirectory, - browserfilter, "", options) + fileName, filtr = QtWidgets.QFileDialog.getOpenFileName( + self, + "Browse for media player executable", + defaultdirectory, + browserfilter, "", options) if fileName: if isMacOS() and fileName.endswith('.app'): # see GitHub issue #91 # Mac OS X application bundles contain a Info.plist in the Contents subdirectory of the .app. @@ -286,7 +294,7 @@ class ConfigDialog(QtWidgets.QDialog): # Step 3: use the first executable in the list if no executable was found try: if not foundExe: - fileName = execFiles[0] + fileName = execFiles[0] except IndexError: # whoops, looks like this .app doesn't contain a executable file at all pass @@ -387,8 +395,9 @@ class ConfigDialog(QtWidgets.QDialog): else: defaultdirectory = "" browserfilter = "All files (*)" - fileName, filtr = QtWidgets.QFileDialog.getOpenFileName(self, "Browse for media files", defaultdirectory, - browserfilter, "", options) + fileName, filtr = QtWidgets.QFileDialog.getOpenFileName( + self, "Browse for media files", defaultdirectory, + browserfilter, "", options) if fileName: self.mediapathTextbox.setText(os.path.normpath(fileName)) self.mediadirectory = os.path.dirname(fileName) @@ -412,7 +421,7 @@ class ConfigDialog(QtWidgets.QDialog): self.processWidget(self, lambda w: self.saveValues(w)) if self.hostCombobox.currentText(): self.config['host'] = self.hostCombobox.currentText() if ":" in self.hostCombobox.currentText() else self.hostCombobox.currentText() + ":" + str(constants.DEFAULT_PORT) - self.config['host'] = self.config['host'].replace(" ","").replace("\t", "").replace("\n","").replace("\r","") + self.config['host'] = self.config['host'].replace(" ", "").replace("\t", "").replace("\n", "").replace("\r", "") else: self.config['host'] = None self.config['playerPath'] = str(self.safenormcaseandpath(self.executablepathCombobox.currentText())) @@ -437,7 +446,7 @@ class ConfigDialog(QtWidgets.QDialog): def keyPressEvent(self, event): if event.key() == Qt.Key_Escape: - sys.exit() + sys.exit() def dragEnterEvent(self, event): data = event.mimeData() @@ -495,7 +504,7 @@ class ConfigDialog(QtWidgets.QDialog): else: widget.setChecked(self.config[valueName] != inverted) elif isinstance(widget, QRadioButton): - radioName, radioValue = valueName.split(constants.CONFIG_NAME_MARKER)[1].split(constants.CONFIG_VALUE_MARKER) + radioName, radioValue = valueName.split(constants.CONFIG_NAME_MARKER)[1].split(constants.CONFIG_VALUE_MARKER) if self.config[radioName] == radioValue: widget.setChecked(True) elif isinstance(widget, QLineEdit): @@ -517,7 +526,7 @@ class ConfigDialog(QtWidgets.QDialog): inverted = False self.config[valueName] = widget.isChecked() != inverted elif isinstance(widget, QRadioButton): - radioName, radioValue = valueName.split(constants.CONFIG_NAME_MARKER)[1].split(constants.CONFIG_VALUE_MARKER) + radioName, radioValue = valueName.split(constants.CONFIG_NAME_MARKER)[1].split(constants.CONFIG_VALUE_MARKER) if widget.isChecked(): self.config[radioName] = radioValue elif isinstance(widget, QLineEdit): @@ -542,10 +551,10 @@ class ConfigDialog(QtWidgets.QDialog): config = self.config playerpaths = self.playerpaths error = self.error - if self.datacleared == True: + if self.datacleared: error = constants.ERROR_MESSAGE_MARKER + "{}".format(getMessage("gui-data-cleared-notification")) self.error = error - if config['host'] == None: + if config['host'] is None: host = "" elif ":" in config['host']: host = config['host'] @@ -566,7 +575,7 @@ class ConfigDialog(QtWidgets.QDialog): serverAddressPort = publicServer[1] self.hostCombobox.addItem(serverAddressPort) self.hostCombobox.setItemData(i, serverTitle, Qt.ToolTipRole) - if not serverAddressPort in self.publicServerAddresses: + if serverAddressPort not in self.publicServerAddresses: self.publicServerAddresses.append(serverAddressPort) i += 1 self.hostCombobox.setEditable(True) @@ -649,8 +658,8 @@ class ConfigDialog(QtWidgets.QDialog): self.mediaplayerSettingsLayout.addWidget(self.executablepathCombobox, 0, 2) self.mediaplayerSettingsLayout.addWidget(self.executablebrowseButton, 0, 3) self.mediaplayerSettingsLayout.addWidget(self.mediapathLabel, 1, 0) - self.mediaplayerSettingsLayout.addWidget(self.mediapathTextbox , 1, 2) - self.mediaplayerSettingsLayout.addWidget(self.mediabrowseButton , 1, 3) + self.mediaplayerSettingsLayout.addWidget(self.mediapathTextbox, 1, 2) + self.mediaplayerSettingsLayout.addWidget(self.mediabrowseButton, 1, 3) self.mediaplayerSettingsLayout.addWidget(self.playerargsLabel, 2, 0, 1, 2) self.mediaplayerSettingsLayout.addWidget(self.playerargsTextbox, 2, 2, 1, 2) self.mediaplayerSettingsGroup.setLayout(self.mediaplayerSettingsLayout) @@ -836,7 +845,7 @@ class ConfigDialog(QtWidgets.QDialog): self.desyncFrame.setMidLineWidth(0) self.desyncSettingsLayout.addWidget(self.slowdownCheckbox, 0, 0, 1, 2, Qt.AlignLeft) - self.desyncSettingsLayout.addWidget(self.rewindCheckbox, 1, 0,1,2, Qt.AlignLeft) + self.desyncSettingsLayout.addWidget(self.rewindCheckbox, 1, 0, 1, 2, Qt.AlignLeft) self.desyncSettingsLayout.setAlignment(Qt.AlignLeft) self.desyncSettingsGroup.setLayout(self.desyncSettingsLayout) @@ -854,7 +863,7 @@ class ConfigDialog(QtWidgets.QDialog): self.othersyncSettingsLayout.addWidget(self.dontslowwithmeCheckbox, 2, 0, 1, 2, Qt.AlignLeft) self.othersyncSettingsLayout.setAlignment(Qt.AlignLeft) - self.othersyncSettingsLayout.addWidget(self.fastforwardCheckbox, 3, 0,1,2, Qt.AlignLeft) + self.othersyncSettingsLayout.addWidget(self.fastforwardCheckbox, 3, 0, 1, 2, Qt.AlignLeft) ## Trusted domains @@ -891,13 +900,13 @@ class ConfigDialog(QtWidgets.QDialog): self.chatInputGroup.setLayout(self.chatInputLayout) self.chatInputEnabledCheckbox = QCheckBox(getMessage("chatinputenabled-label")) self.chatInputEnabledCheckbox.setObjectName("chatInputEnabled") - self.chatInputLayout.addWidget(self.chatInputEnabledCheckbox, 1, 0, 1,1, Qt.AlignLeft) + self.chatInputLayout.addWidget(self.chatInputEnabledCheckbox, 1, 0, 1, 1, Qt.AlignLeft) self.chatDirectInputCheckbox = QCheckBox(getMessage("chatdirectinput-label")) self.chatDirectInputCheckbox.setObjectName("chatDirectInput") self.chatDirectInputCheckbox.setStyleSheet( constants.STYLE_SUBCHECKBOX.format(self.posixresourcespath + "chevrons_right.png")) - self.chatInputLayout.addWidget(self.chatDirectInputCheckbox, 2, 0, 1,1, Qt.AlignLeft) + self.chatInputLayout.addWidget(self.chatDirectInputCheckbox, 2, 0, 1, 1, Qt.AlignLeft) self.inputFontLayout = QtWidgets.QHBoxLayout() self.inputFontLayout.setContentsMargins(0, 0, 0, 0) @@ -959,7 +968,7 @@ class ConfigDialog(QtWidgets.QDialog): self.chatOutputGroup.setLayout(self.chatOutputLayout) self.chatOutputEnabledCheckbox = QCheckBox(getMessage("chatoutputenabled-label")) self.chatOutputEnabledCheckbox.setObjectName("chatOutputEnabled") - self.chatOutputLayout.addWidget(self.chatOutputEnabledCheckbox, 1, 0, 1,1, Qt.AlignLeft) + self.chatOutputLayout.addWidget(self.chatOutputEnabledCheckbox, 1, 0, 1, 1, Qt.AlignLeft) self.outputFontLayout = QtWidgets.QHBoxLayout() self.outputFontLayout.setContentsMargins(0, 0, 0, 0) @@ -1002,7 +1011,7 @@ class ConfigDialog(QtWidgets.QDialog): self.chatOutputLayout.addWidget(self.chatOutputModeFrame) self.subitems['chatOutputEnabled'] = [self.chatOutputModeLabel.objectName(), self.chatOutputChatroomOption.objectName(), - self.chatOutputScrollingOption.objectName(),self.chatOutputFontButton.objectName(), + self.chatOutputScrollingOption.objectName(), self.chatOutputFontButton.objectName(), self.chatOutputFontLabel.objectName()] # chatFrame self.chatFrame.setLayout(self.chatLayout) @@ -1010,7 +1019,7 @@ class ConfigDialog(QtWidgets.QDialog): def fontDialog(self, configName): font = QtGui.QFont() - font.setFamily(self.config[configName+ "FontFamily"]) + font.setFamily(self.config[configName + "FontFamily"]) font.setPointSize(self.config[configName + "RelativeFontSize"]) font.setWeight(self.config[configName + "FontWeight"]) font.setUnderline(self.config[configName + "FontUnderline"]) @@ -1023,7 +1032,7 @@ class ConfigDialog(QtWidgets.QDialog): def colourDialog(self, configName): oldColour = QtGui.QColor() - oldColour.setNamedColor(self.config[configName+ "FontColor"]) + oldColour.setNamedColor(self.config[configName + "FontColor"]) colour = QtWidgets.QColorDialog.getColor(oldColour, self) if colour.isValid(): self.config[configName + "FontColor"] = colour.name() @@ -1145,11 +1154,11 @@ class ConfigDialog(QtWidgets.QDialog): self.bottomButtonLayout.addWidget(self.runButton) self.bottomButtonLayout.addWidget(self.storeAndRunButton) self.bottomButtonFrame.setLayout(self.bottomButtonLayout) - self.bottomButtonLayout.setContentsMargins(5,0,5,0) + self.bottomButtonLayout.setContentsMargins(5, 0, 5, 0) self.mainLayout.addWidget(self.bottomButtonFrame, 1, 0, 1, 2) self.bottomCheckboxFrame = QtWidgets.QFrame() - self.bottomCheckboxFrame.setContentsMargins(0,0,0,0) + self.bottomCheckboxFrame.setContentsMargins(0, 0, 0, 0) self.bottomCheckboxLayout = QtWidgets.QGridLayout() self.alwaysshowCheckbox = QCheckBox(getMessage("forceguiprompt-label")) @@ -1166,12 +1175,12 @@ class ConfigDialog(QtWidgets.QDialog): self.tabListLayout = QtWidgets.QHBoxLayout() self.tabListFrame = QtWidgets.QFrame() self.tabListWidget = QtWidgets.QListWidget() - self.tabListWidget.addItem(QtWidgets.QListWidgetItem(QtGui.QIcon(resourcespath + "house.png"),getMessage("basics-label"))) - self.tabListWidget.addItem(QtWidgets.QListWidgetItem(QtGui.QIcon(resourcespath + "control_pause_blue.png"),getMessage("readiness-label"))) - self.tabListWidget.addItem(QtWidgets.QListWidgetItem(QtGui.QIcon(resourcespath + "film_link.png"),getMessage("sync-label"))) + self.tabListWidget.addItem(QtWidgets.QListWidgetItem(QtGui.QIcon(resourcespath + "house.png"), getMessage("basics-label"))) + self.tabListWidget.addItem(QtWidgets.QListWidgetItem(QtGui.QIcon(resourcespath + "control_pause_blue.png"), getMessage("readiness-label"))) + self.tabListWidget.addItem(QtWidgets.QListWidgetItem(QtGui.QIcon(resourcespath + "film_link.png"), getMessage("sync-label"))) self.tabListWidget.addItem(QtWidgets.QListWidgetItem(QtGui.QIcon(resourcespath + "user_comment.png"), getMessage("chat-label"))) - self.tabListWidget.addItem(QtWidgets.QListWidgetItem(QtGui.QIcon(resourcespath + "error.png"),getMessage("messages-label"))) - self.tabListWidget.addItem(QtWidgets.QListWidgetItem(QtGui.QIcon(resourcespath + "cog.png"),getMessage("misc-label"))) + self.tabListWidget.addItem(QtWidgets.QListWidgetItem(QtGui.QIcon(resourcespath + "error.png"), getMessage("messages-label"))) + self.tabListWidget.addItem(QtWidgets.QListWidgetItem(QtGui.QIcon(resourcespath + "cog.png"), getMessage("misc-label"))) self.tabListLayout.addWidget(self.tabListWidget) self.tabListFrame.setLayout(self.tabListLayout) self.tabListFrame.setFixedWidth(self.tabListFrame.minimumSizeHint().width() + constants.TAB_PADDING) @@ -1224,7 +1233,7 @@ class ConfigDialog(QtWidgets.QDialog): def populateEmptyServerList(self): if self.publicServers is None: - if self.config["checkForUpdatesAutomatically"] == True: + if self.config["checkForUpdatesAutomatically"]: self.updateServerList() else: currentServer = self.hostCombobox.currentText() @@ -1264,7 +1273,7 @@ class ConfigDialog(QtWidgets.QDialog): self._playerProbeThread.done.connect(self._updateExecutableIcon) self._playerProbeThread.start() - if self.config['clearGUIData'] == True: + if self.config['clearGUIData']: self.config['clearGUIData'] = False self.clearGUIData() @@ -1275,7 +1284,7 @@ class ConfigDialog(QtWidgets.QDialog): resourcespath = utils.findWorkingDir() + "\\resources\\" else: resourcespath = utils.findWorkingDir() + "/resources/" - self.posixresourcespath = utils.findWorkingDir().replace("\\","/") + "/resources/" + self.posixresourcespath = utils.findWorkingDir().replace("\\", "/") + "/resources/" self.resourcespath = resourcespath super(ConfigDialog, self).__init__() @@ -1290,7 +1299,7 @@ class ConfigDialog(QtWidgets.QDialog): self.mainLayout = QtWidgets.QGridLayout() self.mainLayout.setSpacing(0) - self.mainLayout.setContentsMargins(0,0,0,0) + self.mainLayout.setContentsMargins(0, 0, 0, 0) self.storedPassword = self.config['password'] self.addBasicTab() @@ -1305,7 +1314,7 @@ class ConfigDialog(QtWidgets.QDialog): self.addBottomLayout() self.updatePasswordVisibilty() - if self.getMoreState() == False: + if not self.getMoreState(): self.tabListFrame.hide() self.resetButton.hide() self.playerargsTextbox.hide() @@ -1321,7 +1330,7 @@ class ConfigDialog(QtWidgets.QDialog): self.mediabrowseButton.show() newHeight = self.connectionSettingsGroup.minimumSizeHint().height()+self.mediaplayerSettingsGroup.minimumSizeHint().height()+self.bottomButtonFrame.minimumSizeHint().height()+3 if self.error: - newHeight +=self.errorLabel.height()+3 + newHeight += self.errorLabel.height() + 3 self.stackedFrame.setFixedHeight(newHeight) else: self.showmoreCheckbox.setChecked(True) diff --git a/syncplay/ui/__init__.py b/syncplay/ui/__init__.py index 74885ff..750240c 100755 --- a/syncplay/ui/__init__.py +++ b/syncplay/ui/__init__.py @@ -1,20 +1,23 @@ import os + if "QT_PREFERRED_BINDING" not in os.environ: os.environ["QT_PREFERRED_BINDING"] = os.pathsep.join( ["PySide2", "PySide", "PyQt5", "PyQt4"] ) - + + try: from syncplay.ui.gui import MainWindow as GraphicalUI except ImportError: pass from syncplay.ui.consoleUI import ConsoleUI + def getUi(graphical=True): - if graphical: #TODO: Add graphical ui + if graphical: # TODO: Add graphical ui ui = GraphicalUI() else: ui = ConsoleUI() ui.setDaemon(True) ui.start() - return ui + return ui diff --git a/syncplay/ui/consoleUI.py b/syncplay/ui/consoleUI.py index 7314f2b..5aff6b8 100755 --- a/syncplay/ui/consoleUI.py +++ b/syncplay/ui/consoleUI.py @@ -1,14 +1,16 @@ -import threading -import time -import syncplay import re -from syncplay import utils -from syncplay import constants -from syncplay.messages import getMessage import sys +import threading +import time + +import syncplay +from syncplay import constants +from syncplay import utils +from syncplay.messages import getMessage from syncplay.utils import formatTime + class ConsoleUI(threading.Thread): def __init__(self): self.promptMode = threading.Event() @@ -16,10 +18,10 @@ class ConsoleUI(threading.Thread): self.promptMode.set() self._syncplayClient = None threading.Thread.__init__(self, name="ConsoleUI") - + def addClient(self, client): self._syncplayClient = client - + def drop(self): pass @@ -28,7 +30,7 @@ class ConsoleUI(threading.Thread): def setPlaylistIndexFilename(self, filename): pass - + def run(self): try: while True: @@ -71,7 +73,7 @@ class ConsoleUI(threading.Thread): if user.file: message = getMessage("userlist-playing-notification").format(username) self.showMessage(message, True) - message = " {}: '{}' ({})".format(getMessage("userlist-file-notification"),user.file['name'], formatTime(user.file['duration'])) + message = " {}: '{}' ({})".format(getMessage("userlist-file-notification"), user.file['name'], formatTime(user.file['duration'])) if currentUser.file: if user.file['name'] == currentUser.file['name'] and user.file['size'] != currentUser.file['size']: message += getMessage("different-filesize-notification") @@ -103,8 +105,8 @@ class ConsoleUI(threading.Thread): def showDebugMessage(self, message): print(message) - def showErrorMessage(self, message, criticalerror = False): - print("ERROR:\t" + message) + def showErrorMessage(self, message, criticalerror=False): + print("ERROR:\t" + message) def _extractSign(self, m): if m: @@ -114,7 +116,7 @@ class ConsoleUI(threading.Thread): return 1 else: return None - + def _tryAdvancedCommands(self, data): o = re.match(constants.UI_OFFSET_REGEX, data) s = re.match(constants.UI_SEEK_REGEX, data) @@ -124,7 +126,7 @@ class ConsoleUI(threading.Thread): if t is None: return if o.group('sign') == "/": - t = self._syncplayClient.getPlayerPosition() - t + t = self._syncplayClient.getPlayerPosition() - t elif sign: t = self._syncplayClient.getUserOffset() + sign * t self._syncplayClient.setUserOffset(t) @@ -135,11 +137,11 @@ class ConsoleUI(threading.Thread): if t is None: return if sign: - t = self._syncplayClient.getGlobalPosition() + sign * t + t = self._syncplayClient.getGlobalPosition() + sign * t self._syncplayClient.setPosition(t) return True - return False - + return False + def executeCommand(self, data): command = re.match(constants.UI_COMMAND_REGEX, data) if not command: @@ -151,14 +153,14 @@ class ConsoleUI(threading.Thread): elif command.group('command') in constants.COMMANDS_LIST: self.getUserlist() elif command.group('command') in constants.COMMANDS_CHAT: - message= command.group('parameter') + message = command.group('parameter') self._syncplayClient.sendChat(message) elif command.group('command') in constants.COMMANDS_PAUSE: self._syncplayClient.setPaused(not self._syncplayClient.getPlayerPaused()) elif command.group('command') in constants.COMMANDS_ROOM: room = command.group('parameter') - if room == None: - if self._syncplayClient.userlist.currentUser.file: + if room is None: + if self._syncplayClient.userlist.currentUser.file: room = self._syncplayClient.userlist.currentUser.file["name"] else: room = self._syncplayClient.defaultRoom @@ -167,7 +169,7 @@ class ConsoleUI(threading.Thread): self._syncplayClient.sendRoom() elif command.group('command') in constants.COMMANDS_CREATE: roombasename = command.group('parameter') - if roombasename == None: + if roombasename is None: roombasename = self._syncplayClient.getRoom() roombasename = utils.stripRoomName(roombasename) self._syncplayClient.createControlledRoom(roombasename) diff --git a/syncplay/ui/gui.py b/syncplay/ui/gui.py index 5c599f7..6cccf4b 100755 --- a/syncplay/ui/gui.py +++ b/syncplay/ui/gui.py @@ -1,28 +1,34 @@ + +import os +import re +import sys +import time +import urllib.error +import urllib.parse +import urllib.request +from datetime import datetime +from functools import wraps + +from twisted.internet import task + +from syncplay import utils, constants, version, revision, release_number +from syncplay.messages import getMessage +from syncplay.ui.consoleUI import ConsoleUI +from syncplay.utils import resourcespath +from syncplay.utils import isLinux, isWindows, isMacOS +from syncplay.utils import formatTime, sameFilename, sameFilesize, sameFileduration, RoomPasswordProvider, formatSize, isURL from syncplay.vendor import Qt from syncplay.vendor.Qt import QtWidgets, QtGui, __binding__, __binding_version__, __qt_version__, IsPySide, IsPySide2 from syncplay.vendor.Qt.QtCore import Qt, QSettings, QSize, QPoint, QUrl, QLine, QDateTime from platform import python_version if IsPySide2: from PySide2.QtCore import QStandardPaths -from syncplay import utils, constants, version, revision, release_number -from syncplay.messages import getMessage -from syncplay.utils import resourcespath -import sys -import time -import urllib.request, urllib.parse, urllib.error -from datetime import datetime -from syncplay.utils import isLinux, isWindows, isMacOS -import re -import os -from syncplay.utils import formatTime, sameFilename, sameFilesize, sameFileduration, RoomPasswordProvider, formatSize, isURL -from functools import wraps -from twisted.internet import task -from syncplay.ui.consoleUI import ConsoleUI if isMacOS() and IsPySide: from Foundation import NSURL from Cocoa import NSString, NSUTF8StringEncoding lastCheckedForUpdates = None + class ConsoleInGUI(ConsoleUI): def showMessage(self, message, noTimestamp=False): self._syncplayClient.ui.showMessage(message, True) @@ -39,6 +45,7 @@ class ConsoleInGUI(ConsoleUI): def getUserlist(self): self._syncplayClient.showUserList(self) + class UserlistItemDelegate(QtWidgets.QStyledItemDelegate): def __init__(self): QtWidgets.QStyledItemDelegate.__init__(self) @@ -62,19 +69,19 @@ class UserlistItemDelegate(QtWidgets.QStyledItemDelegate): userReady = currentQAbstractItemModel.data(itemQModelIndex, Qt.UserRole + constants.USERITEM_READY_ROLE) if roomController and not controlIconQPixmap.isNull(): - itemQPainter.drawPixmap ( + itemQPainter.drawPixmap( optionQStyleOptionViewItem.rect.x()+6, midY-8, controlIconQPixmap.scaled(16, 16, Qt.KeepAspectRatio)) if userReady and not tickIconQPixmap.isNull(): - itemQPainter.drawPixmap ( + itemQPainter.drawPixmap( (optionQStyleOptionViewItem.rect.x()-10), midY - 8, tickIconQPixmap.scaled(16, 16, Qt.KeepAspectRatio)) - elif userReady == False and not crossIconQPixmap.isNull(): - itemQPainter.drawPixmap ( + elif not userReady and not crossIconQPixmap.isNull(): + itemQPainter.drawPixmap( (optionQStyleOptionViewItem.rect.x()-10), midY - 8, crossIconQPixmap.scaled(16, 16, Qt.KeepAspectRatio)) @@ -87,7 +94,7 @@ class UserlistItemDelegate(QtWidgets.QStyledItemDelegate): fileSwitchRole = currentQAbstractItemModel.data(itemQModelIndex, Qt.UserRole + constants.FILEITEM_SWITCH_ROLE) if fileSwitchRole == constants.FILEITEM_SWITCH_FILE_SWITCH: fileSwitchIconQPixmap = QtGui.QPixmap(resourcespath + "film_go.png") - itemQPainter.drawPixmap ( + itemQPainter.drawPixmap( (optionQStyleOptionViewItem.rect.x()), midY - 8, fileSwitchIconQPixmap.scaled(16, 16, Qt.KeepAspectRatio)) @@ -95,64 +102,71 @@ class UserlistItemDelegate(QtWidgets.QStyledItemDelegate): elif fileSwitchRole == constants.FILEITEM_SWITCH_STREAM_SWITCH: streamSwitchIconQPixmap = QtGui.QPixmap(resourcespath + "world_go.png") - itemQPainter.drawPixmap ( + itemQPainter.drawPixmap( (optionQStyleOptionViewItem.rect.x()), midY - 8, streamSwitchIconQPixmap.scaled(16, 16, Qt.KeepAspectRatio)) optionQStyleOptionViewItem.rect.setX(optionQStyleOptionViewItem.rect.x()+16) QtWidgets.QStyledItemDelegate.paint(self, itemQPainter, optionQStyleOptionViewItem, indexQModelIndex) -class AboutDialog(QtWidgets.QDialog): - def __init__(self, parent=None): - super(AboutDialog, self).__init__(parent) - if isMacOS(): - self.setWindowTitle("") - self.setWindowFlags(Qt.Dialog | Qt.WindowTitleHint | Qt.WindowCloseButtonHint | Qt.CustomizeWindowHint) - else: - self.setWindowTitle(getMessage("about-dialog-title")) - if isWindows(): - self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint) - nameLabel = QtWidgets.QLabel("
Copyright © 2012–2018 Syncplay
" + getMessage("about-dialog-license-text") + "
Copyright © 2012–2018 Syncplay
" + + getMessage("about-dialog-license-text") + "