diff --git a/buildPy2exe.py b/buildPy2exe.py index dc6d56c..a81a98d 100755 --- a/buildPy2exe.py +++ b/buildPy2exe.py @@ -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', diff --git a/resources/lua/intf/syncplay.lua b/resources/lua/intf/syncplay.lua index 9b2c459..4f3d07d 100644 --- a/resources/lua/intf/syncplay.lua +++ b/resources/lua/intf/syncplay.lua @@ -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 diff --git a/resources/mpc-be.png b/resources/mpc-be.png new file mode 100644 index 0000000..984887e Binary files /dev/null and b/resources/mpc-be.png differ diff --git a/syncplay/__init__.py b/syncplay/__init__.py index 9dc2334..02e8e74 100644 --- a/syncplay/__init__.py +++ b/syncplay/__init__.py @@ -1,4 +1,4 @@ version = '1.5.0' milestone = 'Yoitsu' -release_number = '47' +release_number = '50' projectURL = 'http://syncplay.pl/' diff --git a/syncplay/constants.py b/syncplay/constants.py index 0a2bdda..707ccea 100644 --- a/syncplay/constants.py +++ b/syncplay/constants.py @@ -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=\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"] \ No newline at end of file +PRIVATE_FILE_FIELDS = ["path"] + +OS_WINDOWS = "win" +OS_LINUX = "linux" +OS_MACOS = "darwin" +OS_BSD = "freebsd" +OS_DRAGONFLY = "dragonfly" \ No newline at end of file diff --git a/syncplay/messages_de.py b/syncplay/messages_de.py index 7af6bff..819ca79 100644 --- a/syncplay/messages_de.py +++ b/syncplay/messages_de.py @@ -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', diff --git a/syncplay/messages_en.py b/syncplay/messages_en.py index dd97e2b..18476cb 100644 --- a/syncplay/messages_en.py +++ b/syncplay/messages_en.py @@ -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', diff --git a/syncplay/messages_ru.py b/syncplay/messages_ru.py index e56f3de..8130c95 100644 --- a/syncplay/messages_ru.py +++ b/syncplay/messages_ru.py @@ -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'пароль к серверу', diff --git a/syncplay/players/__init__.py b/syncplay/players/__init__.py index a1afcb4..710bfe1 100644 --- a/syncplay/players/__init__.py +++ b/syncplay/players/__init__.py @@ -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] diff --git a/syncplay/players/mpc.py b/syncplay/players/mpc.py index c38b074..1dc3064 100644 --- a/syncplay/players/mpc.py +++ b/syncplay/players/mpc.py @@ -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 diff --git a/syncplay/players/mpcbe.py b/syncplay/players/mpcbe.py new file mode 100644 index 0000000..68b2074 --- /dev/null +++ b/syncplay/players/mpcbe.py @@ -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) diff --git a/syncplay/players/mplayer.py b/syncplay/players/mplayer.py index 9e5f855..56e6b4e 100644 --- a/syncplay/players/mplayer.py +++ b/syncplay/players/mplayer.py @@ -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: diff --git a/syncplay/players/vlc.py b/syncplay/players/vlc.py index dde4d5b..bf3826d 100755 --- a/syncplay/players/vlc.py +++ b/syncplay/players/vlc.py @@ -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 diff --git a/syncplay/ui/ConfigurationGetter.py b/syncplay/ui/ConfigurationGetter.py index 79e4f1e..b23814f 100755 --- a/syncplay/ui/ConfigurationGetter.py +++ b/syncplay/ui/ConfigurationGetter.py @@ -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: diff --git a/syncplay/ui/GuiConfiguration.py b/syncplay/ui/GuiConfiguration.py index 2cda809..386326d 100755 --- a/syncplay/ui/GuiConfiguration.py +++ b/syncplay/ui/GuiConfiguration.py @@ -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__() diff --git a/syncplay/ui/gui.py b/syncplay/ui/gui.py index de9c823..298d512 100755 --- a/syncplay/ui/gui.py +++ b/syncplay/ui/gui.py @@ -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("
Syncplay
") nameLabel.setFont(QtGui.QFont("Helvetica", 20)) @@ -109,7 +99,7 @@ class AboutDialog(QtWidgets.QDialog): linkLabel.setOpenExternalLinks(True) versionLabel = QtWidgets.QLabel("
" + getMessage("about-dialog-release").format(version, release_number, __binding__) + "
") licenseLabel = QtWidgets.QLabel("

Copyright © 2017 Syncplay

" + getMessage("about-dialog-license-text") + "

") - 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) diff --git a/syncplay/utils.py b/syncplay/utils.py index 1a7a8ff..402a44d 100644 --- a/syncplay/utils.py +++ b/syncplay/utils.py @@ -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))