Merged upstream/master in master_local

This commit is contained in:
alby128 2017-12-11 18:10:03 +01:00
commit a58995edea
17 changed files with 225 additions and 156 deletions

View File

@ -651,6 +651,7 @@ guiIcons = ['resources/accept.png', 'resources/arrow_undo.png', 'resources/clock
'resources/folder_explore.png', 'resources/help.png', 'resources/table_refresh.png',
'resources/timeline_marker.png','resources/control_play_blue.png',
'resources/mpc-hc.png','resources/mpc-hc64.png','resources/mplayer.png',
'resources/mpc-be.png',
'resources/mpv.png','resources/vlc.png', 'resources/house.png', 'resources/film_link.png',
'resources/eye.png', 'resources/comments.png', 'resources/cog_delete.png', 'resources/chevrons_right.png',
'resources/user_key.png', 'resources/lock.png', 'resources/key_go.png', 'resources/page_white_key.png',

View File

@ -5,7 +5,7 @@
Principal author: Etoh
Other contributors: DerGenaue, jb, Pilotat
Project: http://syncplay.pl/
Version: 0.3.3
Version: 0.3.4
Note:
* This interface module is intended to be used in conjunction with Syncplay.
@ -19,7 +19,7 @@
Place the syncplay.lua file in the main (all user) VLC /lua/intf/ sub-directory:
* Window: %ProgramFiles%\VideoLAN\VLC\lua\intf\
* Linux: /usr/lib/vlc/lua/intf/ or on some systems /usr/lib64/vlc/lua/intf/ (use whichever one already has .luac files in it)
* Linux: /usr/lib/vlc/lua/intf/ or /usr/lib64/vlc/lua/intf/ or /usr/lib/x86_64-linux-gnu/vlc/lua/intf on some systems (look for where the .luac files are)
* Mac OS X: /Applications/VLC.app/Contents/MacOS/share/lua/intf/
* FreeBSD, OpenBSD etc.: /usr/local/lib/vlc/lua/intf/
@ -84,7 +84,7 @@ You may also need to re-copy the syncplay.lua file when you update VLC.
--]==========================================================================]
local connectorversion = "0.3.3"
local connectorversion = "0.3.4"
local vlcversion = vlc.misc.version()
local vlcmajorversion = tonumber(vlcversion:sub(1,1)) -- get the major version of VLC
local durationdelay = 500000 -- Pause for get_duration command etc for increased reliability (uses microseconds)
@ -243,7 +243,7 @@ function get_var( vartoget, fallbackvar )
errormsg = noinput
end
if vlcmajorversion == 3 and vartoget == "time" then
if vlcmajorversion > 2 and vartoget == "time" then
response = response / 1000000
end
@ -257,7 +257,7 @@ function set_var(vartoset, varvalue)
local errormsg
local input = vlc.object.input()
if vlcmajorversion == 3 and vartoset == "time" then
if vlcmajorversion > 2 and vartoset == "time" then
varvalue = varvalue * 1000000
end

BIN
resources/mpc-be.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 890 B

View File

@ -1,4 +1,4 @@
version = '1.5.0'
milestone = 'Yoitsu'
release_number = '47'
release_number = '50'
projectURL = 'http://syncplay.pl/'

View File

@ -83,8 +83,9 @@ COMMANDS_CREATE = ['c','create']
COMMANDS_AUTH = ['a','auth']
COMMANDS_TOGGLE = ['t','toggle']
MPC_MIN_VER = "1.6.4"
MPC_BE_MIN_VER = "1.5.2.3123"
VLC_MIN_VERSION = "2.2.1"
VLC_INTERFACE_MIN_VERSION = "0.3.3"
VLC_INTERFACE_MIN_VERSION = "0.3.4"
VLC_LATENCY_ERROR_THRESHOLD = 2.0
MPV_UNRESPONSIVE_THRESHOLD = 60.0
CONTROLLED_ROOMS_MIN_VERSION = "1.3.0"
@ -105,6 +106,12 @@ MPC_PATHS = [
r"c:\program files\combined community codec pack\mpc\mpc-hc.exe",
r"c:\program files\mpc homecinema (x64)\mpc-hc64.exe",
]
MPC_BE_PATHS = [
r"c:\Program Files\MPC-BE x64\mpc-be64.exe",
r"c:\Program Files\MPC-BE x64\mpc-be.exe",
r"c:\Program Files\MPC-BE\mpc-be64.exe",
r"c:\Program Files\MPC-BE\mpc-be.exe"
]
MPLAYER_PATHS = ["mplayer2", "mplayer"]
MPV_PATHS = ["mpv", "/opt/mpv/mpv", r"c:\program files\mpv\mpv.exe", r"c:\program files\mpv-player\mpv.exe",
r"c:\program Files (x86)\mpv\mpv.exe", r"c:\program Files (x86)\mpv-player\mpv.exe",
@ -124,6 +131,7 @@ MPLAYER_ICONPATH = "mplayer.png"
MPV_ICONPATH = "mpv.png"
MPC_ICONPATH = "mpc-hc.png"
MPC64_ICONPATH = "mpc-hc64.png"
MPC_BE_ICONPATH = "mpc-be.png"
MPV_ERROR_MESSAGES_TO_REPEAT = ['[ytdl_hook] Your version of youtube-dl is too old', '[ytdl_hook] youtube-dl failed', 'Failed to recognize file format.']
@ -173,8 +181,8 @@ MPV_SLAVE_ARGS_NEW = ['--term-playing-msg=<SyncplayUpdateFile>\nANS_filename=${f
MPV_NEW_VERSION = False
VLC_SLAVE_ARGS = ['--extraintf=luaintf', '--lua-intf=syncplay', '--no-quiet', '--no-input-fast-seek',
'--play-and-pause', '--start-time=0']
VLC_SLAVE_OSX_ARGS = ['--verbose=2', '--no-file-logging']
VLC_SLAVE_NONOSX_ARGS = ['--no-one-instance', '--no-one-instance-when-started-from-file']
VLC_SLAVE_MACOS_ARGS = ['--verbose=2', '--no-file-logging']
VLC_SLAVE_NONMACOS_ARGS = ['--no-one-instance', '--no-one-instance-when-started-from-file']
MPV_SUPERSEDE_IF_DUPLICATE_COMMANDS = ["no-osd set time-pos ", "loadfile "]
MPV_REMOVE_BOTH_IF_DUPLICATE_COMMANDS = ["cycle pause"]
MPLAYER_ANSWER_REGEX = "^ANS_([a-zA-Z_-]+)=(.+)$|^(Exiting)\.\.\. \((.+)\)$"
@ -216,4 +224,10 @@ SYNCPLAY_PUBLIC_SERVER_LIST_URL = u"http://syncplay.pl/listpublicservers?{}" # P
DEFAULT_TRUSTED_DOMAINS = [u"youtube.com",u"youtu.be"]
TRUSTABLE_WEB_PROTOCOLS = [u"http://www.",u"https://www.",u"http://",u"https://"]
PRIVATE_FILE_FIELDS = ["path"]
PRIVATE_FILE_FIELDS = ["path"]
OS_WINDOWS = "win"
OS_LINUX = "linux"
OS_MACOS = "darwin"
OS_BSD = "freebsd"
OS_DRAGONFLY = "dragonfly"

View File

@ -108,9 +108,10 @@ de = {
"server-timeout-error" : u"Timeout: Verbindung zum Server fehlgeschlagen",
"mpc-slave-error" : u"Kann MPC nicht im Slave-Modus starten!",
"mpc-version-insufficient-error" : u"MPC-Version nicht ausreichend, bitte nutze `mpc-hc` >= `{}`",
"mpc-be-version-insufficient-error" : u"MPC-Version nicht ausreichend, bitte nutze `mpc-be` >= `{}`",
"mpv-version-error" : u"Syncplay ist nicht kompatibel mit dieser Version von mpv. Bitte benutze eine andere Version (z.B. Git HEAD).",
"player-file-open-error" : u"Fehler beim Öffnen der Datei durch den Player",
"player-path-error" : u"Ungültiger Player-Pfad. Supported players are: mpv, VLC, MPC-HC and mplayer2", # To do: Translate end
"player-path-error" : u"Ungültiger Player-Pfad. Supported players are: mpv, VLC, MPC-HC, MPC-BE and mplayer2", # To do: Translate end
"hostname-empty-error" : u"Hostname darf nicht leer sein",
"empty-error" : u"{} darf nicht leer sein", # Configuration
"media-player-error": u"Player-Fehler: \"{}\"", # Error line
@ -120,7 +121,7 @@ de = {
"unable-to-start-client-error" : u"Client kann nicht gestartet werden",
"player-path-config-error": u"Player-Pfad ist nicht ordnungsgemäß gesetzt. Supported players are: mpv, VLC, MPC-HC and mplayer2.", # To do: Translate end
"player-path-config-error": u"Player-Pfad ist nicht ordnungsgemäß gesetzt. Supported players are: mpv, VLC, MPC-HC, MPC-BE and mplayer2.", # To do: Translate end
"no-file-path-config-error": u"Es muss eine Datei ausgewählt werden, bevor der Player gestartet wird.",
"no-hostname-config-error": u"Hostname darf nicht leer sein",
"invalid-port-config-error" : u"Port muss gültig sein",
@ -151,7 +152,7 @@ de = {
"failed-to-load-server-list-error" : u"Konnte die Liste der öffentlichen Server nicht laden. Bitte besuche http://www.syncplay.pl/ [Englisch] mit deinem Browser.",
# Client arguments
"argument-description" : u'Syncplay ist eine Anwendung um mehrere MPlayer, MPC-HC und VLC-Instanzen über das Internet zu synchronisieren.',
"argument-description" : u'Syncplay ist eine Anwendung um mehrere MPlayer, MPC-HC, MPC-BE und VLC-Instanzen über das Internet zu synchronisieren.',
"argument-epilog" : u'Wenn keine Optionen angegeben sind, werden die _config-Werte verwendet',
"nogui-argument" : u'Keine GUI anzeigen',
"host-argument" : u'Server-Adresse',
@ -195,7 +196,7 @@ de = {
"filename-privacy-label" : u"Dateiname:",
"filesize-privacy-label" : u"Dateigröße:",
"checkforupdatesautomatically-label" : u"Automatisch nach Updates suchen",
"slowondesync-label" : u"Verlangsamen wenn nicht synchron (nicht unterstützt mit MPC-HC)",
"slowondesync-label" : u"Verlangsamen wenn nicht synchron (nicht unterstützt mit MPC-HC/BE)",
"dontslowdownwithme-label" : u"Nie verlangsamen oder andere zurückspulen (Experimentell)",
"pausing-title" : u"Pausing", # TODO: Translate
"pauseonleave-label" : u"Pausieren wenn ein Benutzer austritt",
@ -320,7 +321,7 @@ de = {
"password-tooltip" : u"Passwörter sind nur bei Verbindung zu privaten Servern nötig.",
"room-tooltip" : u"Der Raum, der betreten werden soll, kann ein x-beliebiger sein. Allerdings werden nur Clients im selben Raum synchronisiert.",
"executable-path-tooltip" : u"Pfad zum ausgewählten, unterstützten Mediaplayer (MPC-HC, VLC, mplayer2 or mpv).",
"executable-path-tooltip" : u"Pfad zum ausgewählten, unterstützten Mediaplayer (MPC-HC, MPC-BE, VLC, mplayer2 or mpv).",
"media-path-tooltip" : u"Pfad zum wiederzugebenden Video oder Stream. Notwendig für mplayer2.", # TODO: Confirm translation
"player-arguments-tooltip" : u"Zusätzliche Kommandozeilenparameter / -schalter für diesen Mediaplayer.",
"mediasearcdirectories-arguments-tooltip" : u"Verzeichnisse, in denen Syncplay nach Mediendateien suchen soll, z.B. wenn du das Click-to-switch-Feature verwendest. Syncplay wird rekursiv Unterordner durchsuchen.", # TODO: Translate Click-to-switch? (or use as name for feature)
@ -383,7 +384,7 @@ de = {
"no-salt-notification" : u"WICHTIGER HINWEIS: Damit von dem Server generierte Passwörter für geführte Räume auch nach einem Serverneustart funktionieren, starte den Server mit dem folgenden Parameter: --salt {}", #Salt
# Server arguments
"server-argument-description" : u'Anwendung, um mehrere MPlayer, MPC-HC und VLC-Instanzen über das Internet zu synchronisieren. Server',
"server-argument-description" : u'Anwendung, um mehrere MPlayer, MPC-HC/BE und VLC-Instanzen über das Internet zu synchronisieren. Server',
"server-argument-epilog" : u'Wenn keine Optionen angegeben sind, werden die _config-Werte verwendet',
"server-port-argument" : u'Server TCP-Port',
"server-password-argument" : u'Server Passwort',

View File

@ -107,9 +107,10 @@ en = {
"server-timeout-error" : "Connection with server timed out",
"mpc-slave-error" : "Unable to start MPC in slave mode!",
"mpc-version-insufficient-error" : "MPC version not sufficient, please use `mpc-hc` >= `{}`",
"mpc-be-version-insufficient-error" : "MPC version not sufficient, please use `mpc-be` >= `{}`",
"mpv-version-error" : "Syncplay is not compatible with this version of mpv. Please use a different version of mpv (e.g. Git HEAD).",
"player-file-open-error" : "Player failed opening file",
"player-path-error" : "Player path is not set properly. Supported players are: mpv, VLC, MPC-HC and mplayer2",
"player-path-error" : "Player path is not set properly. Supported players are: mpv, VLC, MPC-HC, MPC-BE and mplayer2",
"hostname-empty-error" : "Hostname can't be empty",
"empty-error" : "{} can't be empty", # Configuration
"media-player-error": "Media player error: \"{}\"", # Error line
@ -119,7 +120,7 @@ en = {
"unable-to-start-client-error" : "Unable to start client",
"player-path-config-error": "Player path is not set properly. Supported players are: mpv, VLC, MPC-HC and mplayer2.",
"player-path-config-error": "Player path is not set properly. Supported players are: mpv, VLC, MPC-HC, MPC-BE and mplayer2.",
"no-file-path-config-error" :"File must be selected before starting your player",
"no-hostname-config-error": "Hostname can't be empty",
"invalid-port-config-error" : "Port must be valid",
@ -149,7 +150,7 @@ en = {
"failed-to-load-server-list-error" : u"Failed to load public server list. Please visit http://www.syncplay.pl/ in your browser.",
# Client arguments
"argument-description" : 'Solution to synchronize playback of multiple MPlayer and MPC-HC instances over the network.',
"argument-description" : 'Solution to synchronize playback of multiple media player instances over the network.',
"argument-epilog" : 'If no options supplied _config values will be used',
"nogui-argument" : 'show no GUI',
"host-argument" : 'server\'s address',
@ -193,7 +194,7 @@ en = {
"filename-privacy-label" : "Filename information:",
"filesize-privacy-label" : "File size information:",
"checkforupdatesautomatically-label" : "Check for Syncplay updates automatically",
"slowondesync-label" : "Slow down on minor desync (not supported on MPC-HC)",
"slowondesync-label" : "Slow down on minor desync (not supported on MPC-HC/BE)",
"rewindondesync-label" : "Rewind on major desync (recommended)",
"fastforwardondesync-label" : "Fast-forward if lagging behind (recommended)",
"dontslowdownwithme-label" : "Never slow down or rewind others (experimental)",
@ -320,7 +321,7 @@ en = {
"password-tooltip" : "Passwords are only needed for connecting to private servers.",
"room-tooltip" : "Room to join upon connection can be almost anything, but you will only be synchronised with people in the same room.",
"executable-path-tooltip" : "Location of your chosen supported media player (mpv, VLC, MPC-HC or mplayer2).",
"executable-path-tooltip" : "Location of your chosen supported media player (mpv, VLC, MPC-HC/BE or mplayer2).",
"media-path-tooltip" : "Location of video or stream to be opened. Necessary for 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 through sub-folders.",
@ -332,7 +333,7 @@ en = {
"privacy-sendhashed-tooltip" : "Send a hashed version of the information, making it less visible to other clients.",
"privacy-dontsend-tooltip" : "Do not send this information to the server. This provides for maximum privacy.",
"checkforupdatesautomatically-tooltip" : "Regularly check with the Syncplay website to see whether a new version of Syncplay is available.",
"slowondesync-tooltip" : "Reduce playback rate temporarily when needed to bring you back in sync with other viewers. Not supported on MPC-HC.",
"slowondesync-tooltip" : "Reduce playback rate temporarily when needed to bring you back in sync with other viewers. Not supported on MPC-HC/BE.",
"dontslowdownwithme-tooltip" : "Means others do not get slowed down or rewinded if your playback is lagging. Useful for room operators.",
"pauseonleave-tooltip" : "Pause playback if you get disconnected or someone leaves from your room.",
"readyatstart-tooltip" : "Set yourself as 'ready' at start (otherwise you are set as 'not ready' until you change your readiness state)",
@ -382,7 +383,7 @@ en = {
# Server arguments
"server-argument-description" : 'Solution to synchronize playback of multiple MPlayer and MPC-HC instances over the network. Server instance',
"server-argument-description" : 'Solution to synchronize playback of multiple MPlayer and MPC-HC/BE instances over the network. Server instance',
"server-argument-epilog" : 'If no options supplied _config values will be used',
"server-port-argument" : 'server TCP port',
"server-password-argument" : 'server password',

View File

@ -108,9 +108,10 @@ ru = {
"server-timeout-error" : u"Подключение к серверу превысило лимит времени",
"mpc-slave-error" : u"Невозможно запустить MPC в slave режиме!",
"mpc-version-insufficient-error" : u"Версия MPC слишком старая, пожалуйста, используйте `mpc-hc` >= `{}`",
"mpc-be-version-insufficient-error" : u"Версия MPC слишком старая, пожалуйста, используйте `mpc-be` >= `{}`",
"mpv-version-error" : u"Syncplay не совместим с данной версией mpv. Пожалуйста, используйте другую версию mpv (лучше свежайшую).",
"player-file-open-error" : u"Проигрыватель не может открыть файл.",
"player-path-error" : u"Путь к проигрывателю задан неверно. Supported players are: mpv, VLC, MPC-HC and mplayer2.", # TODO: Translate last sentence
"player-path-error" : u"Путь к проигрывателю задан неверно. Supported players are: mpv, VLC, MPC-HC, MPC-BE and mplayer2.", # TODO: Translate last sentence
"hostname-empty-error" : u"Имя пользователя не может быть пустым.",
"empty-error" : u"{} не может быть пустым.", # Configuration
"media-player-error" : u"Ошибка проигрывателя: \"{}\"", # Error line
@ -120,7 +121,7 @@ ru = {
"unable-to-start-client-error" : u"Невозможно запустить клиент",
"player-path-config-error": u"Путь к проигрывателю установлен неверно. Supported players are: mpv, VLC, MPC-HC and mplayer2", # To do: Translate end
"player-path-config-error": u"Путь к проигрывателю установлен неверно. Supported players are: mpv, VLC, MPC-HC, MPC-BE and mplayer2", # To do: Translate end
"no-file-path-config-error" : u"Файл должен быть указан до включения проигрывателя",
"no-hostname-config-error": u"Имя сервера не может быть пустым",
"invalid-port-config-error" : u"Неверный номер порта",
@ -151,7 +152,7 @@ ru = {
"failed-to-load-server-list-error" : u"Не удалось загрузить список публичных серверов. Откройте http://www.syncplay.pl/ через браузер.",
# Client arguments
"argument-description" : u'Решение для синхронного воспроизведения в VLC, MPlayer или MPC-HC через Интернет.',
"argument-description" : u'Решение для синхронного воспроизведения в VLC, MPlayer или MPC-HC/BE через Интернет.',
"argument-epilog" : u'Если параметр не будет передан, то будет использоваться значение, указанное в _config.',
"nogui-argument" : u'не использовать GUI',
"host-argument" : u'адрес сервера',
@ -195,7 +196,7 @@ ru = {
"filename-privacy-label" : u"Имя файла:",
"filesize-privacy-label" : u"Размер файла:",
"checkforupdatesautomatically-label" : u"Проверять обновления автоматически",
"slowondesync-label" : u"Замедлять при небольших рассинхронизациях (не поддерживаетя в MPC-HC)",
"slowondesync-label" : u"Замедлять при небольших рассинхронизациях (не поддерживаетя в MPC-HC/BE)",
"rewindondesync-label" : u"Перемотка при больших рассинхронизациях (настоятельно рекомендуется)",
"dontslowdownwithme-label" : u"Никогда не замедлять и не перематывать видео другим (функция тестируется)",
"pausing-title" : u"Приостановка",
@ -322,7 +323,7 @@ ru = {
"password-tooltip" : u"Пароли нужны для подключения к приватным серверам.",
"room-tooltip" : u"Комната, в которую Вы попадете сразу после подключения. Синхронизация возможна только между людьми в одной и той же комнате.",
"executable-path-tooltip" : u"Расположение Вашего видеопроигрывателя (MPC-HC, VLC, mplayer2 или mpv).",
"executable-path-tooltip" : u"Расположение Вашего видеопроигрывателя (MPC-HC, MPC-BE, VLC, mplayer2 или mpv).",
"media-path-tooltip" : u"Расположение видеофайла или потока для просмотра. Обязательно для mplayer2.", # TODO: Confirm translation
"player-arguments-tooltip" : u"Передавать дополнительные аргументы командной строки этому проигрывателю.",
"mediasearcdirectories-arguments-tooltip" : u"Папки, где Syncplay будет искать медиа файлы, включая подпапки.",
@ -334,7 +335,7 @@ ru = {
"privacy-sendhashed-tooltip" : u"Отправляет хэш-сумму этой информации, делая ее невидимой для других пользователей.",
"privacy-dontsend-tooltip" : u"Не отправлять эту информацию на сервер. Предоставляет наибольшую приватность.",
"checkforupdatesautomatically-tooltip" : u"Syncplay будет регулярно заходить на сайт и проверять наличие новых версий.",
"slowondesync-tooltip" : u"Временно уменьшить скорость воспроизведения в целях синхронизации с другими зрителями. Не поддерживается в MPC-HC.",
"slowondesync-tooltip" : u"Временно уменьшить скорость воспроизведения в целях синхронизации с другими зрителями. Не поддерживается в MPC-HC/BE.",
"dontslowdownwithme-tooltip" : u"Ваши лаги не будут влиять на других зрителей.",
"pauseonleave-tooltip" : u"Приостановить воспроизведение, если Вы покинули комнату или кто-то из зрителей отключился от сервера.",
"readyatstart-tooltip" : u"Отметить Вас готовым к просмотру сразу же (по умолчанию Вы отмечены не готовым)",
@ -383,7 +384,7 @@ ru = {
"no-salt-notification" : u"ВНИМАНИЕ: Чтобы сгенерированные сервером пароли операторов комнат работали после перезагрузки сервера, необходимо указать следующий аргумент командной строки при запуске сервера Syncplay: --salt {}", #Salt
# Server arguments
"server-argument-description" : u'Решение для синхронного воспроизведения в VLC, MPlayer или MPC-HC через Интернет. Серверная часть',
"server-argument-description" : u'Решение для синхронного воспроизведения в VLC, MPlayer или MPC-HC/BE через Интернет. Серверная часть',
"server-argument-epilog" : u'Если параметр не будет передан, то будет использоваться значение, указанное в _config.',
"server-port-argument" : u'номер TCP порта сервера',
"server-password-argument" : u'пароль к серверу',

View File

@ -6,6 +6,11 @@ try:
except ImportError:
from syncplay.players.basePlayer import DummyPlayer
MPCHCAPIPlayer = DummyPlayer
try:
from syncplay.players.mpcbe import MpcBePlayer
except ImportError:
from syncplay.players.basePlayer import DummyPlayer
MpcBePlayer = DummyPlayer
def getAvailablePlayers():
return [MPCHCAPIPlayer, MplayerPlayer, MpvPlayer, VlcPlayer]
return [MPCHCAPIPlayer, MplayerPlayer, MpvPlayer, VlcPlayer, MpcBePlayer]

View File

@ -327,6 +327,10 @@ class MPCHCAPIPlayer(BasePlayer):
self.__versionUpdate = threading.Event()
self.__fileUpdate = threading.RLock()
self.__versionUpdate.clear()
@staticmethod
def getMinVersionErrorMessage():
return getMessage("mpc-version-insufficient-error").format(constants.MPC_MIN_VER)
def drop(self):
self.__preventAsking.set()
@ -365,7 +369,7 @@ class MPCHCAPIPlayer(BasePlayer):
def __dropIfNotSufficientVersion(self):
self._mpcApi.askForVersion()
if not self.__versionUpdate.wait(0.1) or not self._mpcApi.version:
self.reactor.callFromThread(self.__client.ui.showErrorMessage, getMessage("mpc-version-insufficient-error").format(constants.MPC_MIN_VER), True)
self.reactor.callFromThread(self.__client.ui.showErrorMessage, self.getMinVersionErrorMessage(), True)
self.reactor.callFromThread(self.__client.stop, True)
def __testMpcReady(self):
@ -382,7 +386,7 @@ class MPCHCAPIPlayer(BasePlayer):
self.reactor.callFromThread(self.__client.ui.showErrorMessage, err.message, True)
self.reactor.callFromThread(self.__client.stop)
def initPlayer(self, filePath):
def initPlayer(self, filePath):
self.__dropIfNotSufficientVersion()
if not self._mpcApi.version:
return

50
syncplay/players/mpcbe.py Normal file
View File

@ -0,0 +1,50 @@
from syncplay import constants
import os.path
from syncplay.messages import getMessage
from syncplay.players.mpc import MPCHCAPIPlayer
class MpcBePlayer(MPCHCAPIPlayer):
@staticmethod
def run(client, playerPath, filePath, args):
args.extend(['/open', '/new'])
mpc = MpcBePlayer(client)
mpc._mpcApi.callbacks.onConnected = lambda: mpc.initPlayer(filePath if filePath else None)
mpc._mpcApi.startMpc(MpcBePlayer.getExpandedPath(playerPath), args)
client.initPlayer(mpc)
return mpc
@staticmethod
def getDefaultPlayerPathsList():
return constants.MPC_BE_PATHS
@staticmethod
def getIconPath(path):
return constants.MPC_BE_ICONPATH
@staticmethod
def isValidPlayerPath(path):
if MpcBePlayer.getExpandedPath(path):
return True
return False
@staticmethod
def getExpandedPath(path):
if os.path.isfile(path):
if path.lower().endswith(u'mpc-be.exe'.lower()) or path.lower().endswith(u'mpc-be64.exe'.lower()):
return path
if os.path.isfile(path + u"mpc-be.exe"):
path += u"mpc-be.exe"
return path
if os.path.isfile(path + u"\\mpc-be.exe"):
path += u"\\mpc-be.exe"
return path
if os.path.isfile(path + u"mpc-be64.exe"):
path += u"mpc-be64.exe"
return path
if os.path.isfile(path + u"\\mpc-be64.exe"):
path += u"\\mpc-be64.exe"
return path
@staticmethod
def getMinVersionErrorMessage():
return getMessage("mpc-be-version-insufficient-error").format(constants.MPC_BE_MIN_VER)

View File

@ -6,6 +6,7 @@ from syncplay.players.basePlayer import BasePlayer
from syncplay import constants, utils
from syncplay.messages import getMessage
import os, sys
from syncplay.utils import isWindows
class MplayerPlayer(BasePlayer):
speedSupported = True
@ -282,7 +283,7 @@ class MplayerPlayer(BasePlayer):
call = [playerPath]
if filePath:
if sys.platform.startswith('win') and not utils.isASCII(filePath):
if isWindows() and not utils.isASCII(filePath):
self.__playerController.delayedFilePath = filePath
filePath = None
else:

View File

@ -11,6 +11,7 @@ import asynchat, asyncore
import urllib
import time
from syncplay.messages import getMessage
from syncplay.utils import isBSD, isLinux, isWindows, isMacOS
class VlcPlayer(BasePlayer):
speedSupported = True
@ -20,10 +21,10 @@ class VlcPlayer(BasePlayer):
RE_ANSWER = re.compile(constants.VLC_ANSWER_REGEX)
SLAVE_ARGS = constants.VLC_SLAVE_ARGS
if sys.platform.startswith('darwin'):
SLAVE_ARGS.extend(constants.VLC_SLAVE_OSX_ARGS)
if isMacOS():
SLAVE_ARGS.extend(constants.VLC_SLAVE_MACOS_ARGS)
else:
SLAVE_ARGS.extend(constants.VLC_SLAVE_NONOSX_ARGS)
SLAVE_ARGS.extend(constants.VLC_SLAVE_NONMACOS_ARGS)
vlcport = random.randrange(constants.VLC_MIN_PORT, constants.VLC_MAX_PORT) if (constants.VLC_MIN_PORT < constants.VLC_MAX_PORT) else constants.VLC_MIN_PORT
def __init__(self, client, playerPath, filePath, args):
@ -146,7 +147,7 @@ class VlcPlayer(BasePlayer):
fileURL = fileURL.replace(u'\\', u'/')
fileURL = fileURL.encode('utf8')
fileURL = urllib.quote_plus(fileURL)
if sys.platform.startswith('win'):
if isWindows():
fileURL = "file:///" + fileURL
else:
fileURL = "file://" + fileURL
@ -331,13 +332,13 @@ class VlcPlayer(BasePlayer):
return False
playerController._client.ui.showErrorMessage(getMessage("vlc-interface-not-installed"))
return False
if sys.platform.startswith('linux'):
if isLinux():
playerController.vlcIntfPath = "/usr/lib/vlc/lua/intf/"
playerController.vlcIntfUserPath = os.path.join(os.getenv('HOME', '.'), ".local/share/vlc/lua/intf/")
elif sys.platform.startswith('darwin'):
elif isMacOS():
playerController.vlcIntfPath = "/Applications/VLC.app/Contents/MacOS/share/lua/intf/"
playerController.vlcIntfUserPath = os.path.join(os.getenv('HOME', '.'), "Library/Application Support/org.videolan.vlc/lua/intf/")
elif 'bsd' in sys.platform or sys.platform.startswith('dragonfly'):
elif isBSD():
# *BSD ports/pkgs install to /usr/local by default.
# This should also work for all the other BSDs, such as OpenBSD or DragonFly.
playerController.vlcIntfPath = "/usr/local/lib/vlc/lua/intf/"
@ -349,7 +350,7 @@ class VlcPlayer(BasePlayer):
if _usevlcintf(playerController.vlcIntfPath, playerController.vlcIntfUserPath):
playerController.SLAVE_ARGS.append('--lua-config=syncplay={{port=\"{}\"}}'.format(str(playerController.vlcport)))
else:
if sys.platform.startswith('linux'):
if isLinux():
playerController.vlcDataPath = "/usr/lib/syncplay/resources"
else:
playerController.vlcDataPath = utils.findWorkingDir() + "\\resources"
@ -387,7 +388,7 @@ class VlcPlayer(BasePlayer):
playerController._client.ui.showErrorMessage(
getMessage("media-player-error").format(line), True)
break
if not sys.platform.startswith('darwin'):
if not isMacOS():
self.__process.stderr = None
else:
vlcoutputthread = threading.Thread(target = self.handle_vlcoutput, args=())
@ -401,7 +402,7 @@ class VlcPlayer(BasePlayer):
self._sendingData = threading.Lock()
def _shouldListenForSTDOUT(self):
if sys.platform.startswith('win'):
if isWindows():
return False # Due to VLC3 not using STDOUT/STDERR
else:
return True

View File

@ -6,6 +6,7 @@ import ast
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
class InvalidConfigValue(Exception):
@ -411,7 +412,7 @@ class ConfigurationGetter(object):
if QCoreApplication.instance() is None:
self.app = QtWidgets.QApplication(sys.argv)
qt5reactor.install()
if sys.platform.startswith('darwin'):
if isMacOS():
import appnope
appnope.nope()
except ImportError:

View File

@ -12,7 +12,8 @@ import sys
import threading
from syncplay.messages import getMessage, getLanguages, setLanguage, getInitialLanguage
from syncplay import constants
from syncplay.utils import isBSD, isLinux, isMacOS
from syncplay.utils import resourcespath, posixresourcespath
class GuiConfiguration:
def __init__(self, config, error=None, defaultConfig=None):
self.defaultConfig = defaultConfig
@ -185,12 +186,12 @@ class ConfigDialog(QtWidgets.QDialog):
def _updateExecutableIcon(self, iconpath, playerpath):
if iconpath is not None and iconpath != "":
if iconpath.endswith('.mng'):
movie = QtGui.QMovie(self.resourcespath + iconpath)
movie = QtGui.QMovie(resourcespath + iconpath)
movie.setCacheMode(QtGui.QMovie.CacheMode.CacheAll)
self.executableiconLabel.setMovie(movie)
movie.start()
else:
self.executableiconImage.load(self.resourcespath + iconpath)
self.executableiconImage.load(resourcespath + iconpath)
self.executableiconLabel.setPixmap(QtGui.QPixmap.fromImage(self.executableiconImage))
else:
self.executableiconLabel.setPixmap(QtGui.QPixmap.fromImage(QtGui.QImage()))
@ -238,11 +239,11 @@ class ConfigDialog(QtWidgets.QDialog):
defaultdirectory = os.environ["ProgramFiles"]
elif "PROGRAMW6432" in os.environ:
defaultdirectory = os.environ["ProgramW6432"]
elif sys.platform.startswith('linux'):
elif isLinux():
defaultdirectory = "/usr/bin"
elif sys.platform.startswith('darwin'):
elif isMacOS():
defaultdirectory = "/Applications/"
elif "bsd" in sys.platform or sys.platform.startswith('dragonfly'):
elif isBSD():
defaultdirectory = "/usr/local/bin"
fileName, filtr = QtWidgets.QFileDialog.getOpenFileName(self,
@ -250,7 +251,7 @@ class ConfigDialog(QtWidgets.QDialog):
defaultdirectory,
browserfilter, "", options)
if fileName:
if sys.platform.startswith('darwin') and fileName.endswith('.app'): # see GitHub issue #91
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.
# This plist file includes the 'CFBundleExecutable' key, which specifies the name of the
# executable. I would have used plistlib here, but since the version of this library in
@ -530,7 +531,6 @@ class ConfigDialog(QtWidgets.QDialog):
def addBasicTab(self):
config = self.config
playerpaths = self.playerpaths
resourcespath = self.resourcespath
error = self.error
if self.datacleared == True:
error = constants.ERROR_MESSAGE_MARKER + "{}".format(getMessage("gui-data-cleared-notification"))
@ -701,22 +701,22 @@ class ConfigDialog(QtWidgets.QDialog):
self.readyUnpauseButtonGroup = QButtonGroup()
self.unpauseIfAlreadyReadyOption = QRadioButton(getMessage("unpause-ifalreadyready-option"))
self.readyUnpauseButtonGroup.addButton(self.unpauseIfAlreadyReadyOption)
self.unpauseIfAlreadyReadyOption.setStyleSheet(constants.STYLE_SUBCHECKBOX.format(self.posixresourcespath + "chevrons_right.png"))
self.unpauseIfAlreadyReadyOption.setStyleSheet(constants.STYLE_SUBCHECKBOX.format(posixresourcespath + "chevrons_right.png"))
self.unpauseIfAlreadyReadyOption.setObjectName("unpause-ifalreadyready" + constants.CONFIG_NAME_MARKER + "unpauseAction" + constants.CONFIG_VALUE_MARKER + constants.UNPAUSE_IFALREADYREADY_MODE)
self.readyUnpauseLayout.addWidget(self.unpauseIfAlreadyReadyOption)
self.unpauseIfOthersReadyOption = QRadioButton(getMessage("unpause-ifothersready-option"))
self.readyUnpauseButtonGroup.addButton(self.unpauseIfOthersReadyOption)
self.unpauseIfOthersReadyOption.setStyleSheet(constants.STYLE_SUBCHECKBOX.format(self.posixresourcespath + "chevrons_right.png"))
self.unpauseIfOthersReadyOption.setStyleSheet(constants.STYLE_SUBCHECKBOX.format(posixresourcespath + "chevrons_right.png"))
self.unpauseIfOthersReadyOption.setObjectName("unpause-ifothersready" + constants.CONFIG_NAME_MARKER + "unpauseAction" + constants.CONFIG_VALUE_MARKER + constants.UNPAUSE_IFOTHERSREADY_MODE)
self.readyUnpauseLayout.addWidget(self.unpauseIfOthersReadyOption)
self.unpauseIfMinUsersReadyOption = QRadioButton(getMessage("unpause-ifminusersready-option"))
self.readyUnpauseButtonGroup.addButton(self.unpauseIfMinUsersReadyOption)
self.unpauseIfMinUsersReadyOption.setStyleSheet(constants.STYLE_SUBCHECKBOX.format(self.posixresourcespath + "chevrons_right.png"))
self.unpauseIfMinUsersReadyOption.setStyleSheet(constants.STYLE_SUBCHECKBOX.format(posixresourcespath + "chevrons_right.png"))
self.unpauseIfMinUsersReadyOption.setObjectName("unpause-ifminusersready" + constants.CONFIG_NAME_MARKER + "unpauseAction" + constants.CONFIG_VALUE_MARKER + constants.UNPAUSE_IFMINUSERSREADY_MODE)
self.readyUnpauseLayout.addWidget(self.unpauseIfMinUsersReadyOption)
self.unpauseAlwaysUnpauseOption = QRadioButton(getMessage("unpause-always"))
self.readyUnpauseButtonGroup.addButton(self.unpauseAlwaysUnpauseOption)
self.unpauseAlwaysUnpauseOption.setStyleSheet(constants.STYLE_SUBCHECKBOX.format(self.posixresourcespath + "chevrons_right.png"))
self.unpauseAlwaysUnpauseOption.setStyleSheet(constants.STYLE_SUBCHECKBOX.format(posixresourcespath + "chevrons_right.png"))
self.unpauseAlwaysUnpauseOption.setObjectName("unpause-always" + constants.CONFIG_NAME_MARKER + "unpauseAction" + constants.CONFIG_VALUE_MARKER + constants.UNPAUSE_ALWAYS_MODE)
self.readyUnpauseLayout.addWidget(self.unpauseAlwaysUnpauseOption)
self.readyLayout.addWidget(self.readyUnpauseGroup)
@ -885,27 +885,27 @@ class ConfigDialog(QtWidgets.QDialog):
self.showSameRoomOSDCheckbox = QCheckBox(getMessage("showsameroomosd-label"))
self.showSameRoomOSDCheckbox.setObjectName("showSameRoomOSD")
self.showSameRoomOSDCheckbox.setStyleSheet(constants.STYLE_SUBCHECKBOX.format(self.posixresourcespath + u"chevrons_right.png"))
self.showSameRoomOSDCheckbox.setStyleSheet(constants.STYLE_SUBCHECKBOX.format(posixresourcespath + u"chevrons_right.png"))
self.osdSettingsLayout.addWidget(self.showSameRoomOSDCheckbox)
self.showNonControllerOSDCheckbox = QCheckBox(getMessage("shownoncontrollerosd-label"))
self.showNonControllerOSDCheckbox.setObjectName("showNonControllerOSD")
self.showNonControllerOSDCheckbox.setStyleSheet(constants.STYLE_SUBCHECKBOX.format(self.posixresourcespath + u"chevrons_right.png"))
self.showNonControllerOSDCheckbox.setStyleSheet(constants.STYLE_SUBCHECKBOX.format(posixresourcespath + u"chevrons_right.png"))
self.osdSettingsLayout.addWidget(self.showNonControllerOSDCheckbox)
self.showDifferentRoomOSDCheckbox = QCheckBox(getMessage("showdifferentroomosd-label"))
self.showDifferentRoomOSDCheckbox.setObjectName("showDifferentRoomOSD")
self.showDifferentRoomOSDCheckbox.setStyleSheet(constants.STYLE_SUBCHECKBOX.format(self.posixresourcespath + u"chevrons_right.png"))
self.showDifferentRoomOSDCheckbox.setStyleSheet(constants.STYLE_SUBCHECKBOX.format(posixresourcespath + u"chevrons_right.png"))
self.osdSettingsLayout.addWidget(self.showDifferentRoomOSDCheckbox)
self.slowdownOSDCheckbox = QCheckBox(getMessage("showslowdownosd-label"))
self.slowdownOSDCheckbox.setObjectName("showSlowdownOSD")
self.slowdownOSDCheckbox.setStyleSheet(constants.STYLE_SUBCHECKBOX.format(self.posixresourcespath + u"chevrons_right.png"))
self.slowdownOSDCheckbox.setStyleSheet(constants.STYLE_SUBCHECKBOX.format(posixresourcespath + u"chevrons_right.png"))
self.osdSettingsLayout.addWidget(self.slowdownOSDCheckbox)
self.showOSDWarningsCheckbox = QCheckBox(getMessage("showosdwarnings-label"))
self.showOSDWarningsCheckbox.setObjectName("showOSDWarnings")
self.showOSDWarningsCheckbox.setStyleSheet(constants.STYLE_SUBCHECKBOX.format(self.posixresourcespath + u"chevrons_right.png"))
self.showOSDWarningsCheckbox.setStyleSheet(constants.STYLE_SUBCHECKBOX.format(posixresourcespath + u"chevrons_right.png"))
self.osdSettingsLayout.addWidget(self.showOSDWarningsCheckbox)
self.subitems['showOSD'] = ["showSameRoomOSD", "showDifferentRoomOSD", "showSlowdownOSD", "showOSDWarnings", "showNonControllerOSD"]
@ -961,11 +961,10 @@ class ConfigDialog(QtWidgets.QDialog):
def addBottomLayout(self):
config = self.config
resourcespath = self.resourcespath
self.bottomButtonFrame = QtWidgets.QFrame()
self.bottomButtonLayout = QtWidgets.QHBoxLayout()
self.helpButton = QtWidgets.QPushButton(QtGui.QIcon(self.resourcespath + u'help.png'), getMessage("help-label"))
self.helpButton = QtWidgets.QPushButton(QtGui.QIcon(resourcespath + u'help.png'), getMessage("help-label"))
self.helpButton.setObjectName("help")
self.helpButton.setMaximumSize(self.helpButton.sizeHint())
self.helpButton.pressed.connect(self.openHelp)
@ -1006,11 +1005,11 @@ class ConfigDialog(QtWidgets.QDialog):
self.tabListLayout = QtWidgets.QHBoxLayout()
self.tabListFrame = QtWidgets.QFrame()
self.tabListWidget = QtWidgets.QListWidget()
self.tabListWidget.addItem(QtWidgets.QListWidgetItem(QtGui.QIcon(self.resourcespath + u"house.png"),getMessage("basics-label")))
self.tabListWidget.addItem(QtWidgets.QListWidgetItem(QtGui.QIcon(self.resourcespath + u"control_pause_blue.png"),getMessage("readiness-label")))
self.tabListWidget.addItem(QtWidgets.QListWidgetItem(QtGui.QIcon(self.resourcespath + u"film_link.png"),getMessage("sync-label")))
self.tabListWidget.addItem(QtWidgets.QListWidgetItem(QtGui.QIcon(self.resourcespath + u"comments.png"),getMessage("messages-label")))
self.tabListWidget.addItem(QtWidgets.QListWidgetItem(QtGui.QIcon(self.resourcespath + u"cog.png"),getMessage("misc-label")))
self.tabListWidget.addItem(QtWidgets.QListWidgetItem(QtGui.QIcon(resourcespath + u"house.png"),getMessage("basics-label")))
self.tabListWidget.addItem(QtWidgets.QListWidgetItem(QtGui.QIcon(resourcespath + u"control_pause_blue.png"),getMessage("readiness-label")))
self.tabListWidget.addItem(QtWidgets.QListWidgetItem(QtGui.QIcon(resourcespath + u"film_link.png"),getMessage("sync-label")))
self.tabListWidget.addItem(QtWidgets.QListWidgetItem(QtGui.QIcon(resourcespath + u"comments.png"),getMessage("messages-label")))
self.tabListWidget.addItem(QtWidgets.QListWidgetItem(QtGui.QIcon(resourcespath + u"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)
@ -1109,12 +1108,6 @@ class ConfigDialog(QtWidgets.QDialog):
self.QtWidgets = QtWidgets
self.QtGui = QtGui
self.error = error
if sys.platform.startswith('win'):
resourcespath = utils.findWorkingDir() + "\\resources\\"
else:
resourcespath = utils.findWorkingDir() + u"/resources/"
self.posixresourcespath = utils.findWorkingDir().replace(u"\\","/") + u"/resources/"
self.resourcespath = resourcespath
super(ConfigDialog, self).__init__()

View File

@ -5,16 +5,18 @@ if IsPySide2:
from PySide2.QtCore import QStandardPaths
from syncplay import utils, constants, version, release_number
from syncplay.messages import getMessage
from syncplay.utils import resourcespath
import sys
import time
import urllib
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
if sys.platform.startswith('darwin') and IsPySide:
if isMacOS() and IsPySide:
from Foundation import NSURL
lastCheckedForUpdates = None
@ -34,10 +36,6 @@ class UserlistItemDelegate(QtWidgets.QStyledItemDelegate):
if column == constants.USERLIST_GUI_USERNAME_COLUMN:
currentQAbstractItemModel = indexQModelIndex.model()
itemQModelIndex = currentQAbstractItemModel.index(indexQModelIndex.row(), constants.USERLIST_GUI_USERNAME_COLUMN, indexQModelIndex.parent())
if sys.platform.startswith('win'):
resourcespath = utils.findWorkingDir() + u"\\resources\\"
else:
resourcespath = utils.findWorkingDir() + u"/resources/"
controlIconQPixmap = QtGui.QPixmap(resourcespath + u"user_key.png")
tickIconQPixmap = QtGui.QPixmap(resourcespath + u"tick.png")
crossIconQPixmap = QtGui.QPixmap(resourcespath + u"cross.png")
@ -65,10 +63,6 @@ class UserlistItemDelegate(QtWidgets.QStyledItemDelegate):
if isUserRow:
optionQStyleOptionViewItem.rect.setX(optionQStyleOptionViewItem.rect.x()+constants.USERLIST_GUI_USERNAME_OFFSET)
if column == constants.USERLIST_GUI_FILENAME_COLUMN:
if sys.platform.startswith('win'):
resourcespath = utils.findWorkingDir() + u"\\resources\\"
else:
resourcespath = utils.findWorkingDir() + u"/resources/"
currentQAbstractItemModel = indexQModelIndex.model()
itemQModelIndex = currentQAbstractItemModel.index(indexQModelIndex.row(), constants.USERLIST_GUI_FILENAME_COLUMN, indexQModelIndex.parent())
fileSwitchRole = currentQAbstractItemModel.data(itemQModelIndex, Qt.UserRole + constants.FILEITEM_SWITCH_ROLE)
@ -90,18 +84,14 @@ class UserlistItemDelegate(QtWidgets.QStyledItemDelegate):
QtWidgets.QStyledItemDelegate.paint(self, itemQPainter, optionQStyleOptionViewItem, indexQModelIndex)
class AboutDialog(QtWidgets.QDialog):
if sys.platform.startswith('win'):
resourcespath = utils.findWorkingDir() + u"\\resources\\"
else:
resourcespath = utils.findWorkingDir() + u"/resources/"
def __init__(self, parent=None):
super(AboutDialog, self).__init__(parent)
if sys.platform.startswith('darwin'):
if isMacOS():
self.setWindowTitle("")
else:
self.setWindowTitle(getMessage("about-dialog-title"))
if sys.platform.startswith('win'):
if isWindows():
self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint)
nameLabel = QtWidgets.QLabel("<center><strong>Syncplay</strong></center>")
nameLabel.setFont(QtGui.QFont("Helvetica", 20))
@ -109,7 +99,7 @@ class AboutDialog(QtWidgets.QDialog):
linkLabel.setOpenExternalLinks(True)
versionLabel = QtWidgets.QLabel("<center>" + getMessage("about-dialog-release").format(version, release_number, __binding__) + "</center>")
licenseLabel = QtWidgets.QLabel("<center><p>Copyright &copy; 2017 Syncplay</p><p>" + getMessage("about-dialog-license-text") + "</p></center>")
aboutIconPixmap = QtGui.QPixmap(self.resourcespath + u"syncplay.png")
aboutIconPixmap = QtGui.QPixmap(resourcespath + u"syncplay.png")
aboutIconLabel = QtWidgets.QLabel()
aboutIconLabel.setPixmap(aboutIconPixmap.scaled(120, 120, Qt.KeepAspectRatio))
aboutLayout = QtWidgets.QGridLayout()
@ -131,16 +121,16 @@ class AboutDialog(QtWidgets.QDialog):
self.setLayout(aboutLayout)
def openLicense(self):
if sys.platform.startswith('win'):
QtGui.QDesktopServices.openUrl(QUrl("file:///" + self.resourcespath + u"license.rtf"))
if isWindows():
QtGui.QDesktopServices.openUrl(QUrl("file:///" + resourcespath + u"license.rtf"))
else:
QtGui.QDesktopServices.openUrl(QUrl("file://" + self.resourcespath + u"license.rtf"))
QtGui.QDesktopServices.openUrl(QUrl("file://" + resourcespath + u"license.rtf"))
def openDependencies(self):
if sys.platform.startswith('win'):
QtGui.QDesktopServices.openUrl(QUrl("file:///" + self.resourcespath + u"third-party-notices.rtf"))
if isWindows():
QtGui.QDesktopServices.openUrl(QUrl("file:///" + resourcespath + u"third-party-notices.rtf"))
else:
QtGui.QDesktopServices.openUrl(QUrl("file://" + self.resourcespath + u"third-party-notices.rtf"))
QtGui.QDesktopServices.openUrl(QUrl("file://" + resourcespath + u"third-party-notices.rtf"))
class MainWindow(QtWidgets.QMainWindow):
insertPosition = None
@ -160,10 +150,6 @@ class MainWindow(QtWidgets.QMainWindow):
itemQPainter.save()
currentQAbstractItemModel = indexQModelIndex.model()
currentlyPlayingFile = currentQAbstractItemModel.data(indexQModelIndex, Qt.UserRole + constants.PLAYLISTITEM_CURRENTLYPLAYING_ROLE)
if sys.platform.startswith('win'):
resourcespath = utils.findWorkingDir() + u"\\resources\\"
else:
resourcespath = utils.findWorkingDir() + u"/resources/"
if currentlyPlayingFile:
currentlyplayingIconQPixmap = QtGui.QPixmap(resourcespath + u"bullet_right_grey.png")
midY = int((optionQStyleOptionViewItem.rect.y() + optionQStyleOptionViewItem.rect.bottomLeft().y()) / 2)
@ -219,7 +205,7 @@ class MainWindow(QtWidgets.QMainWindow):
indexRow = window.playlist.count() if window.clearedPlaylistNote else 0
for url in urls[::-1]:
if sys.platform.startswith('darwin') and IsPySide:
if isMacOS() and IsPySide:
dropfilepath = os.path.abspath(NSURL.URLWithString_(str(url.toString())).filePathURL().path())
else:
dropfilepath = os.path.abspath(unicode(url.toLocalFile()))
@ -324,7 +310,7 @@ class MainWindow(QtWidgets.QMainWindow):
if indexRow == -1:
indexRow = window.playlist.count()
for url in urls[::-1]:
if sys.platform.startswith('darwin') and IsPySide:
if isMacOS() and IsPySide:
dropfilepath = os.path.abspath(NSURL.URLWithString_(str(url.toString())).filePathURL().path())
else:
dropfilepath = os.path.abspath(unicode(url.toLocalFile()))
@ -473,11 +459,11 @@ class MainWindow(QtWidgets.QMainWindow):
if isControlledRoom:
if room == currentUser.room and currentUser.isController():
roomitem.setIcon(QtGui.QPixmap(self.resourcespath + 'lock_open.png'))
roomitem.setIcon(QtGui.QPixmap(resourcespath + 'lock_open.png'))
else:
roomitem.setIcon(QtGui.QPixmap(self.resourcespath + 'lock.png'))
roomitem.setIcon(QtGui.QPixmap(resourcespath + 'lock.png'))
else:
roomitem.setIcon(QtGui.QPixmap(self.resourcespath + 'chevrons_right.png'))
roomitem.setIcon(QtGui.QPixmap(resourcespath + 'chevrons_right.png'))
for user in rooms[room]:
useritem = QtGui.QStandardItem(user.username)
@ -567,10 +553,6 @@ class MainWindow(QtWidgets.QMainWindow):
@needsClient
def openPlaylistMenu(self, position):
indexes = self.playlist.selectedIndexes()
if sys.platform.startswith('win'):
resourcespath = utils.findWorkingDir() + u"\\resources\\"
else:
resourcespath = utils.findWorkingDir() + u"/resources/"
if len(indexes) > 0:
item = self.playlist.selectedIndexes()[0]
else:
@ -609,10 +591,6 @@ class MainWindow(QtWidgets.QMainWindow):
def openRoomMenu(self, position):
# TODO: Deselect items after right click
indexes = self.listTreeView.selectedIndexes()
if sys.platform.startswith('win'):
resourcespath = utils.findWorkingDir() + u"\\resources\\"
else:
resourcespath = utils.findWorkingDir() + u"/resources/"
if len(indexes) > 0:
item = self.listTreeView.selectedIndexes()[0]
else:
@ -872,7 +850,7 @@ class MainWindow(QtWidgets.QMainWindow):
return
self.loadMediaBrowseSettings()
if sys.platform.startswith('darwin') and IsPySide:
if isMacOS() and IsPySide:
options = QtWidgets.QFileDialog.Options(QtWidgets.QFileDialog.DontUseNativeDialog)
else:
options = QtWidgets.QFileDialog.Options()
@ -886,7 +864,7 @@ class MainWindow(QtWidgets.QMainWindow):
fileName, filtr = QtWidgets.QFileDialog.getOpenFileName(self, getMessage("browseformedia-label"), defaultdirectory,
browserfilter, "", options)
if fileName:
if sys.platform.startswith('win'):
if isWindows():
fileName = fileName.replace("/", "\\")
self.mediadirectory = os.path.dirname(fileName)
self._syncplayClient.fileSwitch.setCurrentDirectory(self.mediadirectory)
@ -900,7 +878,7 @@ class MainWindow(QtWidgets.QMainWindow):
return
self.loadMediaBrowseSettings()
if sys.platform.startswith('darwin') and IsPySide:
if isMacOS() and IsPySide:
options = QtWidgets.QFileDialog.Options(QtWidgets.QFileDialog.DontUseNativeDialog)
else:
options = QtWidgets.QFileDialog.Options()
@ -916,7 +894,7 @@ class MainWindow(QtWidgets.QMainWindow):
self.updatingPlaylist = True
if fileNames:
for fileName in fileNames:
if sys.platform.startswith('win'):
if isWindows():
fileName = fileName.replace("/", "\\")
self.mediadirectory = os.path.dirname(fileName)
self._syncplayClient.fileSwitch.setCurrentDirectory(self.mediadirectory)
@ -1051,7 +1029,7 @@ class MainWindow(QtWidgets.QMainWindow):
@needsClient
def openAddMediaDirectoryDialog(self, MediaDirectoriesTextbox, MediaDirectoriesDialog):
if sys.platform.startswith('darwin') and IsPySide:
if isMacOS() and IsPySide:
options = QtWidgets.QFileDialog.Options(QtWidgets.QFileDialog.ShowDirsOnly | QtWidgets.QFileDialog.DontUseNativeDialog)
else:
options = QtWidgets.QFileDialog.Options(QtWidgets.QFileDialog.ShowDirsOnly)
@ -1121,9 +1099,9 @@ class MainWindow(QtWidgets.QMainWindow):
self.showErrorMessage(getMessage("invalid-offset-value"))
def openUserGuide(self):
if sys.platform.startswith('linux'):
if isLinux():
self.QtGui.QDesktopServices.openUrl(QUrl("http://syncplay.pl/guide/linux/"))
elif sys.platform.startswith('win'):
elif isWindows():
self.QtGui.QDesktopServices.openUrl(QUrl("http://syncplay.pl/guide/windows/"))
else:
self.QtGui.QDesktopServices.openUrl(QUrl("http://syncplay.pl/guide/"))
@ -1171,7 +1149,7 @@ class MainWindow(QtWidgets.QMainWindow):
window.chatInput = QtWidgets.QLineEdit()
window.chatInput.setMaxLength(constants.MAX_CHAT_MESSAGE_LENGTH)
window.chatInput.returnPressed.connect(self.sendChatMessage)
window.chatButton = QtWidgets.QPushButton(QtGui.QPixmap(self.resourcespath + 'email_go.png'),
window.chatButton = QtWidgets.QPushButton(QtGui.QPixmap(resourcespath + 'email_go.png'),
getMessage("sendmessage-label"))
window.chatButton.pressed.connect(self.sendChatMessage)
window.chatLayout = QtWidgets.QHBoxLayout()
@ -1226,7 +1204,7 @@ class MainWindow(QtWidgets.QMainWindow):
window.roomInput = QtWidgets.QLineEdit()
window.roomInput.setMaxLength(constants.MAX_ROOM_NAME_LENGTH)
window.roomInput.returnPressed.connect(self.joinRoom)
window.roomButton = QtWidgets.QPushButton(QtGui.QPixmap(self.resourcespath + 'door_in.png'),
window.roomButton = QtWidgets.QPushButton(QtGui.QPixmap(resourcespath + 'door_in.png'),
getMessage("joinroom-label"))
window.roomButton.pressed.connect(self.joinRoom)
window.roomLayout = QtWidgets.QHBoxLayout()
@ -1348,24 +1326,24 @@ class MainWindow(QtWidgets.QMainWindow):
window.playbackFrame.setLayout(window.playbackLayout)
window.seekInput = QtWidgets.QLineEdit()
window.seekInput.returnPressed.connect(self.seekFromButton)
window.seekButton = QtWidgets.QPushButton(QtGui.QPixmap(self.resourcespath + u'clock_go.png'), "")
window.seekButton = QtWidgets.QPushButton(QtGui.QPixmap(resourcespath + u'clock_go.png'), "")
window.seekButton.setToolTip(getMessage("seektime-menu-label"))
window.seekButton.pressed.connect(self.seekFromButton)
window.seekInput.setText("0:00")
window.seekInput.setFixedWidth(60)
window.playbackLayout.addWidget(window.seekInput)
window.playbackLayout.addWidget(window.seekButton)
window.unseekButton = QtWidgets.QPushButton(QtGui.QPixmap(self.resourcespath + u'arrow_undo.png'), "")
window.unseekButton = QtWidgets.QPushButton(QtGui.QPixmap(resourcespath + u'arrow_undo.png'), "")
window.unseekButton.setToolTip(getMessage("undoseek-menu-label"))
window.unseekButton.pressed.connect(self.undoSeek)
window.miscLayout = QtWidgets.QHBoxLayout()
window.playbackLayout.addWidget(window.unseekButton)
window.playButton = QtWidgets.QPushButton(QtGui.QPixmap(self.resourcespath + u'control_play_blue.png'), "")
window.playButton = QtWidgets.QPushButton(QtGui.QPixmap(resourcespath + u'control_play_blue.png'), "")
window.playButton.setToolTip(getMessage("play-menu-label"))
window.playButton.pressed.connect(self.play)
window.playbackLayout.addWidget(window.playButton)
window.pauseButton = QtWidgets.QPushButton(QtGui.QPixmap(self.resourcespath + 'control_pause_blue.png'), "")
window.pauseButton = QtWidgets.QPushButton(QtGui.QPixmap(resourcespath + 'control_pause_blue.png'), "")
window.pauseButton.setToolTip(getMessage("pause-menu-label"))
window.pauseButton.pressed.connect(self.pause)
window.playbackLayout.addWidget(window.pauseButton)
@ -1379,18 +1357,18 @@ class MainWindow(QtWidgets.QMainWindow):
# File menu
window.fileMenu = QtWidgets.QMenu(getMessage("file-menu-label"), self)
window.openAction = window.fileMenu.addAction(QtGui.QPixmap(self.resourcespath + 'folder_explore.png'),
window.openAction = window.fileMenu.addAction(QtGui.QPixmap(resourcespath + 'folder_explore.png'),
getMessage("openmedia-menu-label"))
window.openAction.triggered.connect(self.browseMediapath)
window.openAction = window.fileMenu.addAction(QtGui.QPixmap(self.resourcespath + 'world_explore.png'),
window.openAction = window.fileMenu.addAction(QtGui.QPixmap(resourcespath + 'world_explore.png'),
getMessage("openstreamurl-menu-label"))
window.openAction.triggered.connect(self.promptForStreamURL)
window.openAction = window.fileMenu.addAction(QtGui.QPixmap(self.resourcespath + 'film_folder_edit.png'),
window.openAction = window.fileMenu.addAction(QtGui.QPixmap(resourcespath + 'film_folder_edit.png'),
getMessage("setmediadirectories-menu-label"))
window.openAction.triggered.connect(self.openSetMediaDirectoriesDialog)
window.exitAction = window.fileMenu.addAction(QtGui.QPixmap(self.resourcespath + 'cross.png'),
window.exitAction = window.fileMenu.addAction(QtGui.QPixmap(resourcespath + 'cross.png'),
getMessage("exit-menu-label"))
window.exitAction.triggered.connect(self.exitSyncplay)
window.menuBar.addMenu(window.fileMenu)
@ -1398,13 +1376,13 @@ class MainWindow(QtWidgets.QMainWindow):
# Playback menu
window.playbackMenu = QtWidgets.QMenu(getMessage("playback-menu-label"), self)
window.playAction = window.playbackMenu.addAction(QtGui.QPixmap(self.resourcespath + 'control_play_blue.png'), getMessage("play-menu-label"))
window.playAction = window.playbackMenu.addAction(QtGui.QPixmap(resourcespath + 'control_play_blue.png'), getMessage("play-menu-label"))
window.playAction.triggered.connect(self.play)
window.pauseAction = window.playbackMenu.addAction(QtGui.QPixmap(self.resourcespath + 'control_pause_blue.png'), getMessage("pause-menu-label"))
window.pauseAction = window.playbackMenu.addAction(QtGui.QPixmap(resourcespath + 'control_pause_blue.png'), getMessage("pause-menu-label"))
window.pauseAction.triggered.connect(self.pause)
window.seekAction = window.playbackMenu.addAction(QtGui.QPixmap(self.resourcespath + 'clock_go.png'), getMessage("seektime-menu-label"))
window.seekAction = window.playbackMenu.addAction(QtGui.QPixmap(resourcespath + 'clock_go.png'), getMessage("seektime-menu-label"))
window.seekAction.triggered.connect(self.seekPositionDialog)
window.unseekAction = window.playbackMenu.addAction(QtGui.QPixmap(self.resourcespath + 'arrow_undo.png'), getMessage("undoseek-menu-label"))
window.unseekAction = window.playbackMenu.addAction(QtGui.QPixmap(resourcespath + 'arrow_undo.png'), getMessage("undoseek-menu-label"))
window.unseekAction.triggered.connect(self.undoSeek)
window.menuBar.addMenu(window.playbackMenu)
@ -1412,16 +1390,16 @@ class MainWindow(QtWidgets.QMainWindow):
# Advanced menu
window.advancedMenu = QtWidgets.QMenu(getMessage("advanced-menu-label"), self)
window.setoffsetAction = window.advancedMenu.addAction(QtGui.QPixmap(self.resourcespath + 'timeline_marker.png'),
window.setoffsetAction = window.advancedMenu.addAction(QtGui.QPixmap(resourcespath + 'timeline_marker.png'),
getMessage("setoffset-menu-label"))
window.setoffsetAction.triggered.connect(self.setOffset)
window.setTrustedDomainsAction = window.advancedMenu.addAction(QtGui.QPixmap(self.resourcespath + 'shield_edit.png'),
window.setTrustedDomainsAction = window.advancedMenu.addAction(QtGui.QPixmap(resourcespath + 'shield_edit.png'),
getMessage("settrusteddomains-menu-label"))
window.setTrustedDomainsAction.triggered.connect(self.openSetTrustedDomainsDialog)
window.createcontrolledroomAction = window.advancedMenu.addAction(
QtGui.QPixmap(self.resourcespath + 'page_white_key.png'), getMessage("createcontrolledroom-menu-label"))
QtGui.QPixmap(resourcespath + 'page_white_key.png'), getMessage("createcontrolledroom-menu-label"))
window.createcontrolledroomAction.triggered.connect(self.createControlledRoom)
window.identifyascontroller = window.advancedMenu.addAction(QtGui.QPixmap(self.resourcespath + 'key_go.png'),
window.identifyascontroller = window.advancedMenu.addAction(QtGui.QPixmap(resourcespath + 'key_go.png'),
getMessage("identifyascontroller-menu-label"))
window.identifyascontroller.triggered.connect(self.identifyAsController)
@ -1445,23 +1423,23 @@ class MainWindow(QtWidgets.QMainWindow):
window.helpMenu = QtWidgets.QMenu(getMessage("help-menu-label"), self)
window.userguideAction = window.helpMenu.addAction(QtGui.QPixmap(self.resourcespath + 'help.png'),
window.userguideAction = window.helpMenu.addAction(QtGui.QPixmap(resourcespath + 'help.png'),
getMessage("userguide-menu-label"))
window.userguideAction.triggered.connect(self.openUserGuide)
window.updateAction = window.helpMenu.addAction(QtGui.QPixmap(self.resourcespath + 'application_get.png'),
window.updateAction = window.helpMenu.addAction(QtGui.QPixmap(resourcespath + 'application_get.png'),
getMessage("update-menu-label"))
window.updateAction.triggered.connect(self.userCheckForUpdates)
if not sys.platform.startswith('darwin'):
if not isMacOS():
window.helpMenu.addSeparator()
window.about = window.helpMenu.addAction(QtGui.QPixmap(self.resourcespath + 'syncplay.png'),
window.about = window.helpMenu.addAction(QtGui.QPixmap(resourcespath + 'syncplay.png'),
getMessage("about-menu-label"))
else:
window.about = window.helpMenu.addAction("&About")
window.about.triggered.connect(self.openAbout)
window.menuBar.addMenu(window.helpMenu)
if not sys.platform.startswith('darwin'):
if not isMacOS():
window.mainLayout.setMenuBar(window.menuBar)
def openAbout(self):
@ -1529,16 +1507,16 @@ class MainWindow(QtWidgets.QMainWindow):
def updateReadyIcon(self):
ready = self.readyPushButton.isChecked()
if ready:
self.readyPushButton.setIcon(QtGui.QPixmap(self.resourcespath + 'tick_checkbox.png'))
self.readyPushButton.setIcon(QtGui.QPixmap(resourcespath + 'tick_checkbox.png'))
else:
self.readyPushButton.setIcon(QtGui.QPixmap(self.resourcespath + 'empty_checkbox.png'))
self.readyPushButton.setIcon(QtGui.QPixmap(resourcespath + 'empty_checkbox.png'))
def updateAutoPlayIcon(self):
ready = self.autoplayPushButton.isChecked()
if ready:
self.autoplayPushButton.setIcon(QtGui.QPixmap(self.resourcespath + 'tick_checkbox.png'))
self.autoplayPushButton.setIcon(QtGui.QPixmap(resourcespath + 'tick_checkbox.png'))
else:
self.autoplayPushButton.setIcon(QtGui.QPixmap(self.resourcespath + 'empty_checkbox.png'))
self.autoplayPushButton.setIcon(QtGui.QPixmap(resourcespath + 'empty_checkbox.png'))
def automaticUpdateCheck(self):
currentDateTimeValue = QDateTime.currentDateTime()
@ -1597,7 +1575,7 @@ class MainWindow(QtWidgets.QMainWindow):
data = event.mimeData()
urls = data.urls()
if urls and urls[0].scheme() == 'file':
if sys.platform.startswith('darwin') and IsPySide:
if isMacOS() and IsPySide:
dropfilepath = os.path.abspath(NSURL.URLWithString_(str(url.toString())).filePathURL().path())
else:
dropfilepath = os.path.abspath(unicode(url.toLocalFile()))
@ -1732,11 +1710,7 @@ class MainWindow(QtWidgets.QMainWindow):
self._syncplayClient = None
self.folderSearchEnabled = True
self.QtGui = QtGui
if sys.platform.startswith('win'):
self.resourcespath = utils.findWorkingDir() + u"\\resources\\"
else:
self.resourcespath = utils.findWorkingDir() + u"/resources/"
if sys.platform.startswith('darwin'):
if isMacOS():
self.setWindowFlags(self.windowFlags())
else:
self.setWindowFlags(self.windowFlags() & Qt.AA_DontUseNativeMenuBar)
@ -1747,7 +1721,7 @@ class MainWindow(QtWidgets.QMainWindow):
self.addMenubar(self)
self.addMainFrame(self)
self.loadSettings()
self.setWindowIcon(QtGui.QPixmap(self.resourcespath + u"syncplay.png"))
self.setWindowIcon(QtGui.QPixmap(resourcespath + u"syncplay.png"))
self.setWindowFlags(self.windowFlags() & Qt.WindowCloseButtonHint & Qt.AA_DontUseNativeMenuBar & Qt.WindowMinimizeButtonHint & ~Qt.WindowContextHelpButtonHint)
self.show()
self.setAcceptDrops(True)

View File

@ -17,6 +17,18 @@ import subprocess
folderSearchEnabled = True
def isWindows():
return sys.platform.startswith(constants.OS_WINDOWS)
def isLinux():
return sys.platform.startswith(constants.OS_LINUX)
def isMacOS():
return sys.platform.startswith(constants.OS_MACOS)
def isBSD():
return constants.OS_BSD in sys.platform or sys.platform.startswith(constants.OS_DRAGONFLY)
def retry(ExceptionToCheck, tries=4, delay=3, backoff=2, logger=None):
"""Retry calling the decorated function using an exponential backoff.
@ -125,11 +137,21 @@ def findWorkingDir():
elif frozen in ('dll', 'console_exe', 'windows_exe'):
path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
elif frozen in ('macosx_app'):
path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__)))))
path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__)))))
else:
path = ""
return path
def getResourcesPath():
if isWindows():
return findWorkingDir() + u"\\resources\\"
else:
return findWorkingDir() + u"/resources/"
resourcespath = getResourcesPath()
posixresourcespath = findWorkingDir().replace(u"\\","/") + u"/resources/"
def limitedPowerset(s, minLength):
return itertools.chain.from_iterable(itertools.combinations(s, r) for r in xrange(len(s), minLength, -1))