diff --git a/syncplay/messages.py b/syncplay/messages.py index 78d7368..bc014aa 100755 --- a/syncplay/messages.py +++ b/syncplay/messages.py @@ -134,8 +134,7 @@ en = { "invalid-seek-value" : u"Invalid seek value", "invalid-offset-value" : u"Invalid offset value", - "switch-file-not-found-error" : u"Could not switch to file '{0}' as it was not found in folder '{1}'.", # File not found, folder it was not found in - "switch-no-folder-error" : u"Could not switch to file '{0}'. Syncplay only looks in the folder of the currently playing file, and no file is currently playing.", # File not found + "switch-file-not-found-error" : u"Could not switch to file '{0}'. Syncplay looks in the folder of the currently playing file and specified media directories.", # File not found # Client arguments "argument-description" : 'Solution to synchronize playback of multiple MPlayer and MPC-HC instances over the network.', @@ -204,6 +203,7 @@ en = { "misc-label" : u"Misc", "core-behaviour-title" : "Core room behaviour", "syncplay-internals-title" : u"Syncplay internals", + "syncplay-mediasearchdirectories-title" : u"Directories to search for media (one path per line)", "sync-label" : "Sync", "sync-otherslagging-title" : "If others are lagging behind...", "sync-youlaggging-title" : "If you are lagging behind...", @@ -286,6 +286,7 @@ en = { "executable-path-tooltip" : "Location of your chosen supported media player (MPC-HC, VLC, mplayer2 or mpv).", "media-path-tooltip" : "Location of video or stream to be opened. Necessary for mpv and mplayer2.", "player-arguments-tooltip" : "Additional command line arguments / switches to pass on to this media player.", + "mediasearcdirectories-arguments-tooltip" : u"Directories where Syncplay will search for media files, e.g. when you are using the click to switch feature. Syncplay will look recursively.", "more-tooltip" : "Display less frequently used settings.", "filename-privacy-tooltip" : "Privacy mode for sending currently playing filename to server.", @@ -494,8 +495,7 @@ ru = { "invalid-seek-value" : u"Некорректное значение для перемотки", "invalid-offset-value" : u"Некорректное смещение", - "switch-file-not-found-error" : u"Невозможно переключиться на файл '{0}', т.к. в папке '{1}' его не обнаружено.", # File not found, folder it was not found in - "switch-no-folder-error" : u"Невозможно переключиться на файл '{0}'. Syncplay ищет только в папке проигрываемого файла, а в настоящий момент ничего не проигрывается.", # File not found + "switch-file-not-found-error" : u"Невозможно переключиться на файл '{0}'. Syncplay looks in the folder of the currently playing file and specified media directories.", # File not found # TODO: Translate last part into Russian # Client arguments "argument-description" : u'Решение для синхронного воспроизведения в VLC, MPlayer или MPC-HC через Интернет.', @@ -564,6 +564,7 @@ ru = { "misc-label" : u"Прочее", "core-behaviour-title" : u"Core room behaviour", # TODO: Translate into Russian "syncplay-internals-title" : u"Syncplay internals", # TODO: Translate into Russian + "syncplay-mediasearchdirectories-title" : u"Directories to search for media (one path per line)", # TODO: Translate into Russian "sync-label" : u"Синхронизация", "sync-otherslagging-title" : u"При отставании других зрителей...", "sync-youlaggging-title" : u"Когда я отстаю ...", @@ -646,6 +647,7 @@ ru = { "executable-path-tooltip" : u"Расположение Вашего видеопроигрывателя (MPC-HC, VLC, mplayer2 или mpv).", "media-path-tooltip" : u"Расположение видеофайла или потока для просмотра. Обязательно для mpv и mplayer2.", "player-arguments-tooltip" : u"Передавать дополнительные аргументы командной строки этому проигрывателю.", + "mediasearcdirectories-arguments-tooltip" : u"Directories where Syncplay will search for media files, e.g. when you are using the click to switch feature. Syncplay will look recursively.", # TODO: Translate into Russian "more-tooltip" : u"Показать дополнительные настройки.", "filename-privacy-tooltip" : u"Режим приватности для передачи имени воспроизводимого файла на сервер.", @@ -854,8 +856,7 @@ de = { "invalid-seek-value" : u"Ungültige Zeitangabe", "invalid-offset-value" : u"Ungültiger Offset-Wert", - "switch-file-not-found-error" : u"Could not switch to file '{0}' as it was not found in folder '{1}'.", # File not found, folder it was not found in # TODO: Translate into German - "switch-no-folder-error" : u"Could not switch to file '{0}'. Syncplay only looks in the folder of the currently playing file, and no file is currently playing.", # File not found # TODO: Translate into German + "switch-file-not-found-error" : u"Could not switch to file '{0}'. Syncplay looks in the folder of the currently playing file and specified media directories.", # File not found, folder it was not found in # TODO: Translate into German # Client arguments "argument-description" : u'Syncplay ist eine Anwendung um mehrere MPlayer, MPC-HC und VLC-Instanzen über das Internet zu synchronisieren.', @@ -922,6 +923,7 @@ de = { "misc-label" : u"Diverse", "core-behaviour-title" : u"Verhalten des Raumes", "syncplay-internals-title" : u"Syncplay intern", + "syncplay-mediasearchdirectories-title" : u"Directories to search for media (one path per line)", # TODO: Translate into Russian "sync-label" : u"Synchronisation", "sync-otherslagging-title" : u"Wenn andere laggen...", "sync-youlaggging-title" : u"Wenn du laggst...", @@ -1004,6 +1006,7 @@ de = { "executable-path-tooltip" : u"Pfad zum ausgewählten, unterstützten Mediaplayer (MPC-HC, VLC, mplayer2 or mpv).", "media-path-tooltip" : u"Pfad zum wiederzugebenden Video oder Stream. Notwendig für mpv und mplayer2.", "player-arguments-tooltip" : u"Additional command line arguments / switches to pass on to this media player.", # TODO: Translate into German + "mediasearcdirectories-arguments-tooltip" : u"Directories where Syncplay will search for media files, e.g. when you are using the click to switch feature. Syncplay will look recursively.", # TODO: Translate into German "more-tooltip" : u"Weitere Einstellungen anzeigen.", "filename-privacy-tooltip" : u"Privatheitsmodus beim Senden des Namens der aktuellen Datei zum Server.", diff --git a/syncplay/ui/ConfigurationGetter.py b/syncplay/ui/ConfigurationGetter.py index c73cf60..0fa6284 100755 --- a/syncplay/ui/ConfigurationGetter.py +++ b/syncplay/ui/ConfigurationGetter.py @@ -33,6 +33,7 @@ class ConfigurationGetter(object): "password": None, "playerPath": None, "perPlayerArguments": None, + "mediaSearchDirectories": None, "file": None, "playerArgs": [], "playerClass": None, @@ -108,6 +109,7 @@ class ConfigurationGetter(object): self._serialised = [ "perPlayerArguments", + "mediaSearchDirectories", ] self._numeric = [ @@ -119,7 +121,7 @@ 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"], + "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"] } diff --git a/syncplay/ui/GuiConfiguration.py b/syncplay/ui/GuiConfiguration.py index e059611..c9b5539 100644 --- a/syncplay/ui/GuiConfiguration.py +++ b/syncplay/ui/GuiConfiguration.py @@ -1,6 +1,6 @@ from PySide import QtCore, QtGui from PySide.QtCore import QSettings, Qt, QCoreApplication, QUrl -from PySide.QtGui import QApplication, QLineEdit, QCursor, QLabel, QCheckBox, QDesktopServices, QIcon, QImage, QButtonGroup, QRadioButton, QDoubleSpinBox +from PySide.QtGui import QApplication, QLineEdit, QCursor, QLabel, QCheckBox, QDesktopServices, QIcon, QImage, QButtonGroup, QRadioButton, QDoubleSpinBox, QPlainTextEdit from syncplay.players.playerFactory import PlayerFactory from datetime import datetime from syncplay import utils @@ -250,6 +250,7 @@ class ConfigDialog(QtGui.QDialog): self.loadLastUpdateCheckDate() self.config["perPlayerArguments"] = self.perPlayerArgs + self.config["mediaSearchDirectories"] = utils.convertMultilineStringToList(self.mediasearchTextEdit.toPlainText()) self.processWidget(self, lambda w: self.saveValues(w)) if self.hostTextbox.text(): @@ -381,6 +382,7 @@ class ConfigDialog(QtGui.QDialog): host = config['host'] + ":" + str(config['port']) self.perPlayerArgs = self.config["perPlayerArguments"] + self.mediaSearchDirectories = self.config["mediaSearchDirectories"] self.connectionSettingsGroup = QtGui.QGroupBox(getMessage("connection-group-title")) self.hostTextbox = QLineEdit(host, self) @@ -597,8 +599,21 @@ class ConfigDialog(QtGui.QDialog): self.automaticupdatesCheckbox.setObjectName("checkForUpdatesAutomatically") self.internalSettingsLayout.addWidget(self.automaticupdatesCheckbox) + ## Media path directories + + self.mediasearchSettingsGroup = QtGui.QGroupBox(getMessage("syncplay-mediasearchdirectories-title")) + self.mediasearchSettingsLayout = QtGui.QVBoxLayout() + self.mediasearchSettingsGroup.setLayout(self.mediasearchSettingsLayout) + + self.mediasearchTextEdit = QPlainTextEdit(utils.getListAsMultilineString(self.mediaSearchDirectories)) + self.mediasearchTextEdit.setObjectName(constants.LOAD_SAVE_MANUALLY_MARKER + "mediasearcdirectories-arguments") + self.mediasearchTextEdit.setLineWrapMode(QtGui.QPlainTextEdit.NoWrap) + self.mediasearchSettingsLayout.addWidget(self.mediasearchTextEdit) + self.mediasearchSettingsGroup.setMaximumHeight(self.mediasearchSettingsGroup.minimumSizeHint().height()) + self.miscLayout.addWidget(self.coreSettingsGroup) self.miscLayout.addWidget(self.internalSettingsGroup) + self.miscLayout.addWidget(self.mediasearchSettingsGroup) self.miscLayout.setAlignment(Qt.AlignTop) self.stackedLayout.addWidget(self.miscFrame) diff --git a/syncplay/ui/gui.py b/syncplay/ui/gui.py index 06618a7..3bff6cf 100644 --- a/syncplay/ui/gui.py +++ b/syncplay/ui/gui.py @@ -144,13 +144,18 @@ class MainWindow(QtGui.QMainWindow): def getFileSwitchState(self, filename): if filename: + if filename == getMessage("nofile-note"): + return constants.FILEITEM_SWITCH_NO_SWITCH if self._syncplayClient.userlist.currentUser.file and filename == self._syncplayClient.userlist.currentUser.file['name']: return constants.FILEITEM_SWITCH_NO_SWITCH if isURL(filename): return constants.FILEITEM_SWITCH_STREAM_SWITCH else: currentPath = self._syncplayClient.userlist.currentUser.file["path"] if self._syncplayClient.userlist.currentUser.file else None - if currentPath: + if utils.findFilenameInDirectories(filename, self.config["mediaSearchDirectories"]): + return constants.FILEITEM_SWITCH_FILE_SWITCH + + elif currentPath: currentDirectory = os.path.dirname(currentPath) newPath = os.path.join(currentDirectory, filename) if os.path.isfile(newPath): @@ -293,7 +298,10 @@ class MainWindow(QtGui.QMainWindow): self._syncplayClient._player.openFile(filename) else: currentPath = self._syncplayClient.userlist.currentUser.file["path"] if self._syncplayClient.userlist.currentUser.file else None - if currentPath: + pathFound = utils.findFilenameInDirectories(filename, self.config["mediaSearchDirectories"]) + if pathFound: + self._syncplayClient._player.openFile(pathFound) + elif currentPath: currentDirectory = os.path.dirname(currentPath) newPath = os.path.join(currentDirectory, filename) if os.path.isfile(newPath): @@ -301,7 +309,7 @@ class MainWindow(QtGui.QMainWindow): else: self.showErrorMessage(getMessage("switch-file-not-found-error").format(filename, currentDirectory)) else: - self.showErrorMessage(getMessage("switch-no-folder-error").format(filename)) + self.showErrorMessage(getMessage("switch-file-not-found-error").format(filename)) @needsClient def userListChange(self): diff --git a/syncplay/utils.py b/syncplay/utils.py index 398a77c..ecada19 100644 --- a/syncplay/utils.py +++ b/syncplay/utils.py @@ -241,6 +241,21 @@ def getPlayerArgumentsByPathAsText(arguments, path): argsToReturn = getPlayerArgumentsByPathAsArray(arguments, path) return " ".join(argsToReturn) if argsToReturn else "" +def getListAsMultilineString(pathArray): + return u"\n".join(pathArray) if pathArray else "" + +def convertMultilineStringToList(multilineString): + return unicode.split(multilineString,u"\n") if multilineString else "" + +def findFilenameInDirectories(filename, directoryList): + if filename and directoryList: + for directory in directoryList: + for root, dirs, files in os.walk(directory): + candidatePath = os.path.join(root,filename) + if os.path.isfile(candidatePath): + return candidatePath + return None + class RoomPasswordProvider(object): CONTROLLED_ROOM_REGEX = re.compile("^\+(.*):(\w{12})$") PASSWORD_REGEX = re.compile("[A-Z]{2}-\d{3}-\d{3}")