Revert "Code Syntax Refactoring"

This commit is contained in:
Alberto Sottile 2018-07-23 22:32:47 +02:00 committed by GitHub
parent 995f232a3b
commit 51fba3722f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 2313 additions and 2640 deletions

View File

@ -7,7 +7,6 @@ import os.path
application = defines.get('app', 'dist/Syncplay.app') application = defines.get('app', 'dist/Syncplay.app')
appname = os.path.basename(application) appname = os.path.basename(application)
def icon_from_app(app_path): def icon_from_app(app_path):
plist_path = os.path.join(app_path, 'Contents', 'Info.plist') plist_path = os.path.join(app_path, 'Contents', 'Info.plist')
plist = biplist.readPlist(plist_path) plist = biplist.readPlist(plist_path)
@ -18,7 +17,6 @@ def icon_from_app(app_path):
icon_name = icon_root + icon_ext icon_name = icon_root + icon_ext
return os.path.join(app_path, 'Contents', 'Resources', icon_name) return os.path.join(app_path, 'Contents', 'Resources', icon_name)
# Volume format (see hdiutil create -help) # Volume format (see hdiutil create -help)
format = defines.get('format', 'UDZO') format = defines.get('format', 'UDZO')
@ -29,19 +27,10 @@ compression_level = 9
size = defines.get('size', None) size = defines.get('size', None)
# Files to include # Files to include
files = [ files = [ application, 'resources/lua/intf/.syncplay.lua', 'resources/.macos_vlc_install.command', 'resources/.macOS_readme.pdf' ]
application,
'resources/lua/intf/.syncplay.lua',
'resources/.macos_vlc_install.command',
'resources/.macOS_readme.pdf'
]
# Symlinks to create # Symlinks to create
symlinks = { symlinks = { 'Applications': '/Applications', 'Install for VLC': '.macos_vlc_install.command', 'Read Me': '.macOS_readme.pdf' }
'Applications': '/Applications',
'Install for VLC': '.macos_vlc_install.command',
'Read Me': '.macOS_readme.pdf'
}
# Volume icon # Volume icon
# #

View File

@ -5,8 +5,8 @@
#*** TROUBLESHOOTING *** #*** TROUBLESHOOTING ***
#1) If you get the error "ImportError: No module named zope.interface" then add an empty __init__.py file to the PYTHONDIR/Lib/site-packages/zope directory #1) If you get the error "ImportError: No module named zope.interface" then add an empty __init__.py file to the PYTHONDIR/Lib/site-packages/zope directory
#2) It is expected that you will have NSIS 3 NSIS from http://nsis.sourceforge.net installed. #2) It is expected that you will have NSIS 3 NSIS from http://nsis.sourceforge.net installed.
import codecs
import sys import sys, codecs
# try: # try:
# if (sys.version_info.major != 2) or (sys.version_info.minor < 7): # if (sys.version_info.major != 2) or (sys.version_info.minor < 7):
# raise Exception("You must build Syncplay with Python 2.7!") # raise Exception("You must build Syncplay with Python 2.7!")
@ -14,20 +14,18 @@ import sys
# import warnings # import warnings
# warnings.warn("You must build Syncplay with Python 2.7!") # warnings.warn("You must build Syncplay with Python 2.7!")
import os
import subprocess
from string import Template from string import Template
import syncplay import syncplay
import os
import subprocess
from syncplay.messages import getMissingStrings from syncplay.messages import getMissingStrings
missingStrings = getMissingStrings() missingStrings = getMissingStrings()
if missingStrings is not None and missingStrings is not "": if missingStrings is not None and missingStrings is not "":
import warnings import warnings
warnings.warn("MISSING/UNUSED STRINGS DETECTED:\n{}".format(missingStrings)) warnings.warn("MISSING/UNUSED STRINGS DETECTED:\n{}".format(missingStrings))
def get_nsis_path(): def get_nsis_path():
bin_name = "makensis.exe" bin_name = "makensis.exe"
from winreg import HKEY_LOCAL_MACHINE as HKLM from winreg import HKEY_LOCAL_MACHINE as HKLM
@ -41,11 +39,9 @@ def get_nsis_path():
raise Exception("You must install NSIS 3 or later.") raise Exception("You must install NSIS 3 or later.")
except WindowsError: except WindowsError:
return bin_name return bin_name
NSIS_COMPILE = get_nsis_path() NSIS_COMPILE = get_nsis_path()
OUT_DIR = r"dist\Syncplay" OUT_DIR = "dist\Syncplay"
SETUP_SCRIPT_PATH = "syncplay_setup.nsi" SETUP_SCRIPT_PATH = "syncplay_setup.nsi"
NSIS_SCRIPT_TEMPLATE = r""" NSIS_SCRIPT_TEMPLATE = r"""
!include LogicLib.nsh !include LogicLib.nsh
@ -612,7 +608,6 @@ NSIS_SCRIPT_TEMPLATE = r"""
SectionEnd SectionEnd
""" """
class NSISScript(object): class NSISScript(object):
def create(self): def create(self):
fileList, totalSize = self.getBuildDirContents(OUT_DIR) fileList, totalSize = self.getBuildDirContents(OUT_DIR)
@ -669,9 +664,7 @@ class NSISScript(object):
delete.append('RMdir "$INSTDIR\\{}"'.format(file_)) delete.append('RMdir "$INSTDIR\\{}"'.format(file_))
return "\n".join(delete) return "\n".join(delete)
guiIcons = ['resources/accept.png', 'resources/arrow_undo.png', 'resources/clock_go.png',
guiIcons = [
'resources/accept.png', 'resources/arrow_undo.png', 'resources/clock_go.png',
'resources/control_pause_blue.png', 'resources/cross.png', 'resources/door_in.png', 'resources/control_pause_blue.png', 'resources/cross.png', 'resources/door_in.png',
'resources/folder_explore.png', 'resources/help.png', 'resources/table_refresh.png', 'resources/folder_explore.png', 'resources/help.png', 'resources/table_refresh.png',
'resources/timeline_marker.png','resources/control_play_blue.png', 'resources/timeline_marker.png','resources/control_play_blue.png',
@ -693,13 +686,7 @@ guiIcons = [
'resources/email_go.png', 'resources/email_go.png',
'resources/world_add.png', 'resources/film_add.png', 'resources/delete.png', 'resources/spinner.mng' 'resources/world_add.png', 'resources/film_add.png', 'resources/delete.png', 'resources/spinner.mng'
] ]
resources = [ resources = ["resources/icon.ico", "resources/syncplay.png", "resources/syncplayintf.lua", "resources/license.rtf", "resources/third-party-notices.rtf"]
"resources/icon.ico",
"resources/syncplay.png",
"resources/syncplayintf.lua",
"resources/license.rtf",
"resources/third-party-notices.rtf"
]
resources.extend(guiIcons) resources.extend(guiIcons)
intf_resources = ["resources/lua/intf/syncplay.lua"] intf_resources = ["resources/lua/intf/syncplay.lua"]

View File

@ -18,12 +18,7 @@ OPTIONS = {
'extra_scripts': 'syncplayServer.py', 'extra_scripts': 'syncplayServer.py',
'includes': {'PySide2.QtCore', 'PySide2.QtUiTools', 'PySide2.QtGui','PySide2.QtWidgets', 'certifi'}, 'includes': {'PySide2.QtCore', 'PySide2.QtUiTools', 'PySide2.QtGui','PySide2.QtWidgets', 'certifi'},
'excludes': {'PySide', 'PySide.QtCore', 'PySide.QtUiTools', 'PySide.QtGui'}, 'excludes': {'PySide', 'PySide.QtCore', 'PySide.QtUiTools', 'PySide.QtGui'},
'qt_plugins': [ 'qt_plugins': ['platforms/libqcocoa.dylib', 'platforms/libqminimal.dylib','platforms/libqoffscreen.dylib', 'styles/libqmacstyle.dylib'],
'platforms/libqcocoa.dylib',
'platforms/libqminimal.dylib',
'platforms/libqoffscreen.dylib',
'styles/libqmacstyle.dylib'
],
'plist': { 'plist': {
'CFBundleName':'Syncplay', 'CFBundleName':'Syncplay',
'CFBundleShortVersionString':syncplay.version, 'CFBundleShortVersionString':syncplay.version,

View File

@ -6,8 +6,7 @@
#1) If you get the error "ImportError: No module named zope.interface" then add an empty __init__.py file to the PYTHONDIR/Lib/site-packages/zope directory #1) If you get the error "ImportError: No module named zope.interface" then add an empty __init__.py file to the PYTHONDIR/Lib/site-packages/zope directory
#2) It is expected that you will have NSIS 3 NSIS from http://nsis.sourceforge.net installed. #2) It is expected that you will have NSIS 3 NSIS from http://nsis.sourceforge.net installed.
import codecs import sys, codecs
import sys
# try: # try:
# if (sys.version_info.major != 2) or (sys.version_info.minor < 7): # if (sys.version_info.major != 2) or (sys.version_info.minor < 7):
# raise Exception("You must build Syncplay with Python 2.7!") # raise Exception("You must build Syncplay with Python 2.7!")
@ -15,26 +14,23 @@ import sys
# import warnings # import warnings
# warnings.warn("You must build Syncplay with Python 2.7!") # warnings.warn("You must build Syncplay with Python 2.7!")
import os
import subprocess
from string import Template
from distutils.core import setup from distutils.core import setup
try: try:
from py2exe.build_exe import py2exe from py2exe.build_exe import py2exe
except ImportError: except ImportError:
from py2exe.distutils_buildexe import py2exe from py2exe.distutils_buildexe import py2exe
from string import Template
import syncplay import syncplay
from syncplay.messages import getMissingStrings import os
import subprocess
from syncplay.messages import getMissingStrings
missingStrings = getMissingStrings() missingStrings = getMissingStrings()
if missingStrings is not None and missingStrings is not "": if missingStrings is not None and missingStrings is not "":
import warnings import warnings
warnings.warn("MISSING/UNUSED STRINGS DETECTED:\n{}".format(missingStrings)) warnings.warn("MISSING/UNUSED STRINGS DETECTED:\n{}".format(missingStrings))
def get_nsis_path(): def get_nsis_path():
bin_name = "makensis.exe" bin_name = "makensis.exe"
from winreg import HKEY_LOCAL_MACHINE as HKLM from winreg import HKEY_LOCAL_MACHINE as HKLM
@ -48,8 +44,6 @@ def get_nsis_path():
raise Exception("You must install NSIS 3 or later.") raise Exception("You must install NSIS 3 or later.")
except WindowsError: except WindowsError:
return bin_name return bin_name
NSIS_COMPILE = get_nsis_path() NSIS_COMPILE = get_nsis_path()
OUT_DIR = "syncplay_v{}".format(syncplay.version) OUT_DIR = "syncplay_v{}".format(syncplay.version)
@ -619,7 +613,6 @@ NSIS_SCRIPT_TEMPLATE = r"""
SectionEnd SectionEnd
""" """
class NSISScript(object): class NSISScript(object):
def create(self): def create(self):
fileList, totalSize = self.getBuildDirContents(OUT_DIR) fileList, totalSize = self.getBuildDirContents(OUT_DIR)
@ -676,7 +669,6 @@ class NSISScript(object):
delete.append('RMdir "$INSTDIR\\{}"'.format(file_)) delete.append('RMdir "$INSTDIR\\{}"'.format(file_))
return "\n".join(delete) return "\n".join(delete)
class build_installer(py2exe): class build_installer(py2exe):
def run(self): def run(self):
py2exe.run(self) py2exe.run(self)
@ -686,9 +678,7 @@ class build_installer(py2exe):
script.compile() script.compile()
print("*** DONE ***") print("*** DONE ***")
guiIcons = ['resources/accept.png', 'resources/arrow_undo.png', 'resources/clock_go.png',
guiIcons = [
'resources/accept.png', 'resources/arrow_undo.png', 'resources/clock_go.png',
'resources/control_pause_blue.png', 'resources/cross.png', 'resources/door_in.png', 'resources/control_pause_blue.png', 'resources/cross.png', 'resources/door_in.png',
'resources/folder_explore.png', 'resources/help.png', 'resources/table_refresh.png', 'resources/folder_explore.png', 'resources/help.png', 'resources/table_refresh.png',
'resources/timeline_marker.png','resources/control_play_blue.png', 'resources/timeline_marker.png','resources/control_play_blue.png',
@ -710,13 +700,7 @@ guiIcons = [
'resources/email_go.png', 'resources/email_go.png',
'resources/world_add.png', 'resources/film_add.png', 'resources/delete.png', 'resources/spinner.mng' 'resources/world_add.png', 'resources/film_add.png', 'resources/delete.png', 'resources/spinner.mng'
] ]
resources = [ resources = ["resources/icon.ico", "resources/syncplay.png", "resources/syncplayintf.lua", "resources/license.rtf", "resources/third-party-notices.rtf"]
"resources/icon.ico",
"resources/syncplay.png",
"resources/syncplayintf.lua",
"resources/license.rtf",
"resources/third-party-notices.rtf"
]
resources.extend(guiIcons) resources.extend(guiIcons)
intf_resources = ["resources/lua/intf/syncplay.lua"] intf_resources = ["resources/lua/intf/syncplay.lua"]
@ -730,16 +714,11 @@ common_info = dict(
info = dict( info = dict(
common_info, common_info,
windows=[{ windows=[{"script":"syncplayClient.py", "icon_resources":[(1, "resources\\icon.ico")], 'dest_base': "Syncplay"},],
"script": "syncplayClient.py",
"icon_resources": [(1, "resources\\icon.ico")],
'dest_base': "Syncplay"},
],
console=['syncplayServer.py'], console=['syncplayServer.py'],
# *** If you wish to make the Syncplay client use console mode (for --no-gui to work) then comment out the above two lines and uncomment the following line: # *** If you wish to make the Syncplay client use console mode (for --no-gui to work) then comment out the above two lines and uncomment the following line:
# console=['syncplayServer.py', {"script":"syncplayClient.py", "icon_resources":[(1, "resources\\icon.ico")], 'dest_base': "Syncplay"}], # console=['syncplayServer.py', {"script":"syncplayClient.py", "icon_resources":[(1, "resources\\icon.ico")], 'dest_base': "Syncplay"}],
options={ options={'py2exe': {
'py2exe': {
'dist_dir': OUT_DIR, 'dist_dir': OUT_DIR,
'packages': 'PySide.QtUiTools', 'packages': 'PySide.QtUiTools',
'includes': 'twisted, sys, encodings, datetime, os, time, math, PySide, liburl, ast, unicodedata, _ssl', 'includes': 'twisted, sys, encodings, datetime, os, time, math, PySide, liburl, ast, unicodedata, _ssl',

View File

@ -1,27 +1,22 @@
import ast
import collections
import hashlib import hashlib
import os.path import os.path
import random import time
import re import re
import sys import sys
import ast
import random
import threading import threading
import time
from copy import deepcopy
from functools import wraps
from twisted.internet.protocol import ClientFactory from twisted.internet.protocol import ClientFactory
from twisted.internet import reactor, task, defer, threads from twisted.internet import reactor, task, defer, threads
from functools import wraps
from copy import deepcopy
from syncplay.protocols import SyncClientProtocol
from syncplay import utils, constants, version from syncplay import utils, constants, version
from syncplay.utils import isMacOS
from syncplay.messages import getMissingStrings, getMessage
from syncplay.constants import PRIVACY_SENDHASHED_MODE, PRIVACY_DONTSEND_MODE, \ from syncplay.constants import PRIVACY_SENDHASHED_MODE, PRIVACY_DONTSEND_MODE, \
PRIVACY_HIDDENFILENAME PRIVACY_HIDDENFILENAME
from syncplay.messages import getMissingStrings, getMessage import collections
from syncplay.protocols import SyncClientProtocol
from syncplay.utils import isMacOS
class SyncClientFactory(ClientFactory): class SyncClientFactory(ClientFactory):
def __init__(self, client, retry=constants.RECONNECT_RETRIES): def __init__(self, client, retry=constants.RECONNECT_RETRIES):
self._client = client self._client = client
@ -63,7 +58,6 @@ class SyncClientFactory(ClientFactory):
def stopRetrying(self): def stopRetrying(self):
self._timesTried = self.retry self._timesTried = self.retry
class SyncplayClient(object): class SyncplayClient(object):
def __init__(self, playerClass, ui, config): def __init__(self, playerClass, ui, config):
constants.SHOW_OSD = config['showOSD'] constants.SHOW_OSD = config['showOSD']
@ -209,19 +203,12 @@ class SyncplayClient(object):
self._playerPosition = position self._playerPosition = position
self._playerPaused = paused self._playerPaused = paused
currentLength = self.userlist.currentUser.file["duration"] if self.userlist.currentUser.file else 0 currentLength = self.userlist.currentUser.file["duration"] if self.userlist.currentUser.file else 0
if ( if pauseChange and paused and currentLength > constants.PLAYLIST_LOAD_NEXT_FILE_MINIMUM_LENGTH\
pauseChange and paused and currentLength > constants.PLAYLIST_LOAD_NEXT_FILE_MINIMUM_LENGTH and abs(position - currentLength ) < constants.PLAYLIST_LOAD_NEXT_FILE_TIME_FROM_END_THRESHOLD:
and abs(position - currentLength) < constants.PLAYLIST_LOAD_NEXT_FILE_TIME_FROM_END_THRESHOLD
):
self.playlist.advancePlaylistCheck() self.playlist.advancePlaylistCheck()
elif pauseChange and "readiness" in self.serverFeatures and self.serverFeatures["readiness"]: elif pauseChange and "readiness" in self.serverFeatures and self.serverFeatures["readiness"]:
if ( if currentLength == 0 or currentLength == -1 or\
currentLength == 0 or currentLength == -1 or not (not self.playlist.notJustChangedPlaylist() and abs(position - currentLength ) < constants.PLAYLIST_LOAD_NEXT_FILE_TIME_FROM_END_THRESHOLD):
not (
not self.playlist.notJustChangedPlaylist() and
abs(position - currentLength) < constants.PLAYLIST_LOAD_NEXT_FILE_TIME_FROM_END_THRESHOLD
)
):
pauseChange = self._toggleReady(pauseChange, paused) pauseChange = self._toggleReady(pauseChange, paused)
if self._lastGlobalUpdate: if self._lastGlobalUpdate:
@ -317,7 +304,7 @@ class SyncplayClient(object):
self.setPosition(self.getGlobalPosition()) self.setPosition(self.getGlobalPosition())
self._player.setPaused(True) self._player.setPaused(True)
madeChangeOnPlayer = True madeChangeOnPlayer = True
if (self.lastLeftTime < time.time() - constants.OSD_DURATION) or hideFromOSD: if (self.lastLeftTime < time.time() - constants.OSD_DURATION) or (hideFromOSD == True):
self.ui.showMessage(getMessage("pause-notification").format(setBy), hideFromOSD) self.ui.showMessage(getMessage("pause-notification").format(setBy), hideFromOSD)
else: else:
self.ui.showMessage(getMessage("left-paused-notification").format(self.lastLeftUser, setBy), hideFromOSD) self.ui.showMessage(getMessage("left-paused-notification").format(self.lastLeftUser, setBy), hideFromOSD)
@ -364,9 +351,9 @@ class SyncplayClient(object):
self._lastGlobalUpdate = time.time() self._lastGlobalUpdate = time.time()
if doSeek: if doSeek:
madeChangeOnPlayer = self._serverSeeked(position, setBy) madeChangeOnPlayer = self._serverSeeked(position, setBy)
if diff > self._config['rewindThreshold'] and not doSeek and self._config['rewindOnDesync']: if diff > self._config['rewindThreshold'] and not doSeek and not self._config['rewindOnDesync'] == False:
madeChangeOnPlayer = self._rewindPlayerDueToTimeDifference(position, setBy) madeChangeOnPlayer = self._rewindPlayerDueToTimeDifference(position, setBy)
if self._config['fastforwardOnDesync'] and (not self.userlist.currentUser.canControl() or self._config['dontSlowDownWithMe']): if self._config['fastforwardOnDesync'] and (self.userlist.currentUser.canControl() == False or self._config['dontSlowDownWithMe'] == True):
if diff < (constants.FASTFORWARD_BEHIND_THRESHOLD * -1) and not doSeek: if diff < (constants.FASTFORWARD_BEHIND_THRESHOLD * -1) and not doSeek:
if self.behindFirstDetected is None: if self.behindFirstDetected is None:
self.behindFirstDetected = time.time() self.behindFirstDetected = time.time()
@ -378,11 +365,11 @@ class SyncplayClient(object):
self.behindFirstDetected = time.time() + constants.FASTFORWARD_RESET_THRESHOLD self.behindFirstDetected = time.time() + constants.FASTFORWARD_RESET_THRESHOLD
else: else:
self.behindFirstDetected = None self.behindFirstDetected = None
if self._player.speedSupported and not doSeek and not paused and self._config['slowOnDesync']: if self._player.speedSupported and not doSeek and not paused and not self._config['slowOnDesync'] == False:
madeChangeOnPlayer = self._slowDownToCoverTimeDifference(diff, setBy) madeChangeOnPlayer = self._slowDownToCoverTimeDifference(diff, setBy)
if not paused and pauseChanged: if paused == False and pauseChanged:
madeChangeOnPlayer = self._serverUnpaused(setBy) madeChangeOnPlayer = self._serverUnpaused(setBy)
elif paused and pauseChanged: elif paused == True and pauseChanged:
madeChangeOnPlayer = self._serverPaused(setBy) madeChangeOnPlayer = self._serverPaused(setBy)
return madeChangeOnPlayer return madeChangeOnPlayer
@ -579,11 +566,11 @@ class SyncplayClient(object):
constants.MAX_ROOM_NAME_LENGTH = self.serverFeatures["maxRoomNameLength"] constants.MAX_ROOM_NAME_LENGTH = self.serverFeatures["maxRoomNameLength"]
if self.serverFeatures["maxFilenameLength"] is not None: if self.serverFeatures["maxFilenameLength"] is not None:
constants.MAX_FILENAME_LENGTH = self.serverFeatures["maxFilenameLength"] constants.MAX_FILENAME_LENGTH = self.serverFeatures["maxFilenameLength"]
constants.MPV_SYNCPLAYINTF_CONSTANTS_TO_SEND = [ constants.MPV_SYNCPLAYINTF_CONSTANTS_TO_SEND = ["MaxChatMessageLength={}".format(constants.MAX_CHAT_MESSAGE_LENGTH),
"MaxChatMessageLength={}".format(constants.MAX_CHAT_MESSAGE_LENGTH),
"inputPromptStartCharacter={}".format(constants.MPV_INPUT_PROMPT_START_CHARACTER), "inputPromptStartCharacter={}".format(constants.MPV_INPUT_PROMPT_START_CHARACTER),
"inputPromptEndCharacter={}".format(constants.MPV_INPUT_PROMPT_END_CHARACTER), "inputPromptEndCharacter={}".format(constants.MPV_INPUT_PROMPT_END_CHARACTER),
"backslashSubstituteCharacter={}".format(constants.MPV_INPUT_BACKSLASH_SUBSTITUTE_CHARACTER)] "backslashSubstituteCharacter={}".format(
constants.MPV_INPUT_BACKSLASH_SUBSTITUTE_CHARACTER)]
self.ui.setFeatures(self.serverFeatures) self.ui.setFeatures(self.serverFeatures)
if self._player: if self._player:
self._player.setFeatures(self.serverFeatures) self._player.setFeatures(self.serverFeatures)
@ -599,6 +586,7 @@ class SyncplayClient(object):
else: else:
return None return None
def sendFile(self): def sendFile(self):
file_ = self.getSanitizedCurrentUserFile() file_ = self.getSanitizedCurrentUserFile()
if self._protocol and self._protocol.logged and file_: if self._protocol and self._protocol.logged and file_:
@ -774,7 +762,7 @@ class SyncplayClient(object):
from syncplay.ui.ConfigurationGetter import ConfigurationGetter from syncplay.ui.ConfigurationGetter import ConfigurationGetter
ConfigurationGetter().setConfigOption("sharedPlaylistEnabled", newState) ConfigurationGetter().setConfigOption("sharedPlaylistEnabled", newState)
self._config["sharedPlaylistEnabled"] = newState self._config["sharedPlaylistEnabled"] = newState
if not oldState and newState: if oldState == False and newState == True:
self.playlist.loadCurrentPlaylistIndex() self.playlist.loadCurrentPlaylistIndex()
def changeAutoplayState(self, newState): def changeAutoplayState(self, newState):
@ -785,7 +773,7 @@ class SyncplayClient(object):
oldAutoplayConditionsMet = self.autoplayConditionsMet() oldAutoplayConditionsMet = self.autoplayConditionsMet()
self.autoPlayThreshold = newThreshold self.autoPlayThreshold = newThreshold
newAutoplayConditionsMet = self.autoplayConditionsMet() newAutoplayConditionsMet = self.autoplayConditionsMet()
if not oldAutoplayConditionsMet and newAutoplayConditionsMet: if oldAutoplayConditionsMet == False and newAutoplayConditionsMet == True:
self.autoplayCheck() self.autoplayCheck()
def autoplayCheck(self): def autoplayCheck(self):
@ -811,12 +799,9 @@ class SyncplayClient(object):
def autoplayConditionsMet(self): def autoplayConditionsMet(self):
recentlyReset = (self.lastRewindTime is not None and abs(time.time() - self.lastRewindTime) < 10) and self._playerPosition < 3 recentlyReset = (self.lastRewindTime is not None and abs(time.time() - self.lastRewindTime) < 10) and self._playerPosition < 3
return ( return self._playerPaused and (self.autoPlay or recentlyReset) and self.userlist.currentUser.canControl() and self.userlist.isReadinessSupported()\
self._playerPaused and (self.autoPlay or recentlyReset) and and self.userlist.areAllUsersInRoomReady(requireSameFilenames=self._config["autoplayRequireSameFilenames"])\
self.userlist.currentUser.canControl() and self.userlist.isReadinessSupported()
and self.userlist.areAllUsersInRoomReady(requireSameFilenames=self._config["autoplayRequireSameFilenames"])
and ((self.autoPlayThreshold and self.userlist.usersInRoomCount() >= self.autoPlayThreshold) or recentlyReset) and ((self.autoPlayThreshold and self.userlist.usersInRoomCount() >= self.autoPlayThreshold) or recentlyReset)
)
def autoplayTimerIsRunning(self): def autoplayTimerIsRunning(self):
return self.autoplayTimer.running return self.autoplayTimer.running
@ -1064,7 +1049,6 @@ class SyncplayClient(object):
elif not self._userlist.currentUser.isReady(): # CurrentUser should always be reminded they are set to not ready elif not self._userlist.currentUser.isReady(): # CurrentUser should always be reminded they are set to not ready
self.checkReadyStates() self.checkReadyStates()
class SyncplayUser(object): class SyncplayUser(object):
def __init__(self, username=None, room=None, file_=None): def __init__(self, username=None, room=None, file_=None):
self.ready = None self.ready = None
@ -1129,7 +1113,6 @@ class SyncplayUser(object):
def setFeatures(self, features): def setFeatures(self, features):
self._features = features self._features = features
class SyncplayUserlist(object): class SyncplayUserlist(object):
def __init__(self, ui, client): def __init__(self, ui, client):
self.currentUser = SyncplayUser() self.currentUser = SyncplayUser()
@ -1158,7 +1141,7 @@ class SyncplayUserlist(object):
showOnOSD = constants.SHOW_OSD_WARNINGS showOnOSD = constants.SHOW_OSD_WARNINGS
else: else:
showOnOSD = constants.SHOW_DIFFERENT_ROOM_OSD showOnOSD = constants.SHOW_DIFFERENT_ROOM_OSD
if constants.SHOW_NONCONTROLLER_OSD == False and not self.canControl(username): if constants.SHOW_NONCONTROLLER_OSD == False and self.canControl(username) == False:
showOnOSD = False showOnOSD = False
hideFromOSD = not showOnOSD hideFromOSD = not showOnOSD
if not file_: if not file_:
@ -1275,16 +1258,12 @@ class SyncplayUserlist(object):
return False return False
for user in self._users.values(): for user in self._users.values():
if user.room == self.currentUser.room: if user.room == self.currentUser.room:
if not user.isReadyWithFile() == False: if user.isReadyWithFile() == False:
return False return False
elif ( elif requireSameFilenames and\
requireSameFilenames and (self.currentUser.file is None
(
self.currentUser.file is None
or user.file is None or user.file is None
or not utils.sameFilename(self.currentUser.file['name'], user.file['name']) or not utils.sameFilename(self.currentUser.file['name'], user.file['name'])):
)
):
return False return False
return True return True
@ -1415,7 +1394,6 @@ class SyncplayUserlist(object):
rooms = collections.OrderedDict(sorted(list(rooms.items()), key=lambda s: s[0].lower())) rooms = collections.OrderedDict(sorted(list(rooms.items()), key=lambda s: s[0].lower()))
return rooms return rooms
class UiManager(object): class UiManager(object):
def __init__(self, client, ui): def __init__(self, client, ui):
self._client = client self._client = client
@ -1451,8 +1429,7 @@ class UiManager(object):
self.__ui.showMessage(messageString) self.__ui.showMessage(messageString)
def showMessage(self, message, noPlayer=False, noTimestamp=False, OSDType=constants.OSD_NOTIFICATION,mood=constants.MESSAGE_NEUTRAL): def showMessage(self, message, noPlayer=False, noTimestamp=False, OSDType=constants.OSD_NOTIFICATION,mood=constants.MESSAGE_NEUTRAL):
if not noPlayer: if not noPlayer: self.showOSDMessage(message, duration=constants.OSD_DURATION, OSDType=OSDType, mood=mood)
self.showOSDMessage(message, duration=constants.OSD_DURATION, OSDType=OSDType, mood=mood)
self.__ui.showMessage(message, noTimestamp) self.__ui.showMessage(message, noTimestamp)
def updateAutoPlayState(self, newState): def updateAutoPlayState(self, newState):
@ -1510,7 +1487,6 @@ class UiManager(object):
def drop(self): def drop(self):
self.__ui.drop() self.__ui.drop()
class SyncplayPlaylist(): class SyncplayPlaylist():
def __init__(self, client): def __init__(self, client):
self._client = client self._client = client
@ -1710,11 +1686,9 @@ class SyncplayPlaylist():
def advancePlaylistCheck(self): def advancePlaylistCheck(self):
position = self._client.getStoredPlayerPosition() position = self._client.getStoredPlayerPosition()
currentLength = self._client.userlist.currentUser.file["duration"] if self._client.userlist.currentUser.file else 0 currentLength = self._client.userlist.currentUser.file["duration"] if self._client.userlist.currentUser.file else 0
if ( if currentLength > constants.PLAYLIST_LOAD_NEXT_FILE_MINIMUM_LENGTH\
currentLength > constants.PLAYLIST_LOAD_NEXT_FILE_MINIMUM_LENGTH and and abs(position - currentLength ) < constants.PLAYLIST_LOAD_NEXT_FILE_TIME_FROM_END_THRESHOLD\
abs(position - currentLength) < constants.PLAYLIST_LOAD_NEXT_FILE_TIME_FROM_END_THRESHOLD and and self.notJustChangedPlaylist():
self.notJustChangedPlaylist()
):
self.loadNextFileInPlaylist() self.loadNextFileInPlaylist()
def notJustChangedPlaylist(self): def notJustChangedPlaylist(self):
@ -1785,7 +1759,6 @@ class SyncplayPlaylist():
def _playlistBufferNeedsUpdating(self, newPlaylist): def _playlistBufferNeedsUpdating(self, newPlaylist):
return self._previousPlaylist != self._playlist and self._playlist != newPlaylist return self._previousPlaylist != self._playlist and self._playlist != newPlaylist
class FileSwitchManager(object): class FileSwitchManager(object):
def __init__(self, client): def __init__(self, client):
self._client = client self._client = client

View File

@ -1,8 +1,6 @@
from syncplay.ui.ConfigurationGetter import ConfigurationGetter
from syncplay import ui from syncplay import ui
from syncplay.messages import getMessage from syncplay.messages import getMessage
from syncplay.ui.ConfigurationGetter import ConfigurationGetter
class SyncplayClientManager(object): class SyncplayClientManager(object):
def run(self): def run(self):
@ -15,3 +13,4 @@ class SyncplayClientManager(object):
syncplayClient.start(config['host'], config['port']) syncplayClient.start(config['host'], config['port'])
else: else:
interface.showErrorMessage(getMessage("unable-to-start-client-error"), True) interface.showErrorMessage(getMessage("unable-to-start-client-error"), True)

View File

@ -16,12 +16,7 @@ SHOW_CONTACT_INFO = True # Displays dev contact details below list in GUI
SHOW_TOOLTIPS = True SHOW_TOOLTIPS = True
WARN_ABOUT_MISSING_STRINGS = False # (If debug mode is enabled) WARN_ABOUT_MISSING_STRINGS = False # (If debug mode is enabled)
FALLBACK_INITIAL_LANGUAGE = "en" FALLBACK_INITIAL_LANGUAGE = "en"
FALLBACK_PUBLIC_SYNCPLAY_SERVERS = [ FALLBACK_PUBLIC_SYNCPLAY_SERVERS = [['syncplay.pl:8995 (France)', 'syncplay.pl:8995'],['syncplay.pl:8996 (France)', 'syncplay.pl:8996'],['syncplay.pl:8997 (France)', 'syncplay.pl:8997'],['syncplay.pl:8998 (France)', 'syncplay.pl:8998'],['syncplay.pl:8999 (France)', 'syncplay.pl:8999']]
['syncplay.pl:8995 (France)', 'syncplay.pl:8995'],
['syncplay.pl:8996 (France)', 'syncplay.pl:8996'],
['syncplay.pl:8997 (France)', 'syncplay.pl:8997'],
['syncplay.pl:8998 (France)', 'syncplay.pl:8998'],
['syncplay.pl:8999 (France)', 'syncplay.pl:8999']]
PLAYLIST_LOAD_NEXT_FILE_MINIMUM_LENGTH = 10 # Seconds PLAYLIST_LOAD_NEXT_FILE_MINIMUM_LENGTH = 10 # Seconds
PLAYLIST_LOAD_NEXT_FILE_TIME_FROM_END_THRESHOLD = 5 # Seconds (only triggered if file is paused, e.g. due to EOF) PLAYLIST_LOAD_NEXT_FILE_TIME_FROM_END_THRESHOLD = 5 # Seconds (only triggered if file is paused, e.g. due to EOF)
@ -205,11 +200,7 @@ MPV_SYNCPLAYINTF_OPTIONS_TO_SEND = ["chatInputEnabled", "chatInputFontFamily", "
"chatTopMargin","chatLeftMargin","chatBottomMargin","chatDirectInput", "chatTopMargin","chatLeftMargin","chatBottomMargin","chatDirectInput",
"notificationTimeout","alertTimeout","chatTimeout","chatOutputEnabled"] "notificationTimeout","alertTimeout","chatTimeout","chatOutputEnabled"]
MPV_SYNCPLAYINTF_CONSTANTS_TO_SEND = [ MPV_SYNCPLAYINTF_CONSTANTS_TO_SEND = ["MaxChatMessageLength={}".format(MAX_CHAT_MESSAGE_LENGTH),"inputPromptStartCharacter={}".format(MPV_INPUT_PROMPT_START_CHARACTER),"inputPromptEndCharacter={}".format(MPV_INPUT_PROMPT_END_CHARACTER),"backslashSubstituteCharacter={}".format(MPV_INPUT_BACKSLASH_SUBSTITUTE_CHARACTER)]
"MaxChatMessageLength={}".format(MAX_CHAT_MESSAGE_LENGTH),
"inputPromptStartCharacter={}".format(MPV_INPUT_PROMPT_START_CHARACTER),
"inputPromptEndCharacter={}".format(MPV_INPUT_PROMPT_END_CHARACTER),
"backslashSubstituteCharacter={}".format(MPV_INPUT_BACKSLASH_SUBSTITUTE_CHARACTER)]
# Note: Constants updated in client.py->checkForFeatureSupport # Note: Constants updated in client.py->checkForFeatureSupport
MPV_SYNCPLAYINTF_LANGUAGE_TO_SEND = ["mpv-key-tab-hint","mpv-key-hint", "alphakey-mode-warning-first-line", "alphakey-mode-warning-second-line"] MPV_SYNCPLAYINTF_LANGUAGE_TO_SEND = ["mpv-key-tab-hint","mpv-key-hint", "alphakey-mode-warning-first-line", "alphakey-mode-warning-second-line"]
VLC_SLAVE_ARGS = ['--extraintf=luaintf', '--lua-intf=syncplay', '--no-quiet', '--no-input-fast-seek', VLC_SLAVE_ARGS = ['--extraintf=luaintf', '--lua-intf=syncplay', '--no-quiet', '--no-input-fast-seek',

View File

@ -14,7 +14,6 @@ messages = {
"CURRENT": None "CURRENT": None
} }
def getLanguages(): def getLanguages():
langList = {} langList = {}
for lang in messages: for lang in messages:
@ -22,11 +21,9 @@ def getLanguages():
langList[lang] = getMessage("LANGUAGE", lang) langList[lang] = getMessage("LANGUAGE", lang)
return langList return langList
def setLanguage(lang): def setLanguage(lang):
messages["CURRENT"] = lang messages["CURRENT"] = lang
def getMissingStrings(): def getMissingStrings():
missingStrings = "" missingStrings = ""
for lang in messages: for lang in messages:
@ -40,7 +37,6 @@ def getMissingStrings():
return missingStrings return missingStrings
def getInitialLanguage(): def getInitialLanguage():
import locale import locale
try: try:
@ -51,11 +47,9 @@ def getInitialLanguage():
initialLanguage = constants.FALLBACK_INITIAL_LANGUAGE initialLanguage = constants.FALLBACK_INITIAL_LANGUAGE
return initialLanguage return initialLanguage
def isValidLanguage(language): def isValidLanguage(language):
return language in messages return language in messages
def getMessage(type_, locale=None): def getMessage(type_, locale=None):
if constants.SHOW_TOOLTIPS == False: if constants.SHOW_TOOLTIPS == False:
if "-tooltip" in type_: if "-tooltip" in type_:

View File

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

View File

@ -1,6 +1,4 @@
from syncplay import constants from syncplay import constants
class BasePlayer(object): class BasePlayer(object):
''' '''
@ -14,9 +12,7 @@ class BasePlayer(object):
''' '''
Display given message on player's OSD or similar means Display given message on player's OSD or similar means
''' '''
def displayMessage( def displayMessage(self, message, duration = (constants.OSD_DURATION*1000), secondaryOSD=False, mood=constants.MESSAGE_NEUTRAL):
self, message, duration=(constants.OSD_DURATION*1000), secondaryOSD=False, mood=constants.MESSAGE_NEUTRAL
):
raise NotImplementedError() raise NotImplementedError()
''' '''
@ -62,6 +58,7 @@ class BasePlayer(object):
def openFile(self, filePath, resetPosition=False): def openFile(self, filePath, resetPosition=False):
raise NotImplementedError() raise NotImplementedError()
''' '''
@return: list of strings @return: list of strings
''' '''
@ -110,7 +107,6 @@ class BasePlayer(object):
def getPlayerPathErrors(playerPath, filePath): def getPlayerPathErrors(playerPath, filePath):
raise NotImplementedError() raise NotImplementedError()
class DummyPlayer(BasePlayer): class DummyPlayer(BasePlayer):
@staticmethod @staticmethod

View File

@ -1,18 +1,15 @@
#coding:utf8
import os.path
import re
import time import time
import threading import threading
import _thread import _thread
from functools import wraps
import win32con, win32api, win32gui, ctypes, ctypes.wintypes #@UnresolvedImport @UnusedImport import win32con, win32api, win32gui, ctypes, ctypes.wintypes #@UnresolvedImport @UnusedImport
from functools import wraps
from syncplay.players.basePlayer import BasePlayer
import re
from syncplay.utils import retry
from syncplay import constants from syncplay import constants
from syncplay.messages import getMessage from syncplay.messages import getMessage
from syncplay.players.basePlayer import BasePlayer import os.path
from syncplay.utils import retry
class MpcHcApi: class MpcHcApi:
def __init__(self): def __init__(self):
@ -52,7 +49,7 @@ class MpcHcApi:
self.__listener.SendCommand(self.CMD_OPENFILE, filePath) self.__listener.SendCommand(self.CMD_OPENFILE, filePath)
def isPaused(self): def isPaused(self):
return self.playState != self.__MPC_PLAYSTATE.PS_PLAY and self.playState is not None return self.playState != self.__MPC_PLAYSTATE.PS_PLAY and self.playState != None
def askForVersion(self): def askForVersion(self):
self.__listener.SendCommand(self.CMD_GETVERSION) self.__listener.SendCommand(self.CMD_GETVERSION)
@ -106,11 +103,7 @@ class MpcHcApi:
elif cmd == self.CMD_STATE: elif cmd == self.CMD_STATE:
self.loadState = int(value) self.loadState = int(value)
fileNotReady = ( fileNotReady = self.loadState == self.__MPC_LOADSTATE.MLS_CLOSING or self.loadState == self.__MPC_LOADSTATE.MLS_LOADING or self.loadState == self.__MPC_LOADSTATE.MLS_CLOSED
self.loadState == self.__MPC_LOADSTATE.MLS_CLOSING or
self.loadState == self.__MPC_LOADSTATE.MLS_LOADING or
self.loadState == self.__MPC_LOADSTATE.MLS_CLOSED
)
if fileNotReady: if fileNotReady:
self.playState = None self.playState = None
self.__locks.fileReady.clear() self.__locks.fileReady.clear()
@ -279,6 +272,7 @@ class MpcHcApi:
self.locks.listenerStart.set() self.locks.listenerStart.set()
win32gui.PumpMessages() win32gui.PumpMessages()
def OnCopyData(self, hwnd, msg, wparam, lparam): def OnCopyData(self, hwnd, msg, wparam, lparam):
pCDS = ctypes.cast(lparam, self.__PCOPYDATASTRUCT) pCDS = ctypes.cast(lparam, self.__PCOPYDATASTRUCT)
#print "API:\tin>\t 0x%X\t" % int(pCDS.contents.dwData), ctypes.wstring_at(pCDS.contents.lpData) #print "API:\tin>\t 0x%X\t" % int(pCDS.contents.dwData), ctypes.wstring_at(pCDS.contents.lpData)
@ -310,7 +304,6 @@ class MpcHcApi:
('lpData', ctypes.c_void_p) ('lpData', ctypes.c_void_p)
] ]
class MPCHCAPIPlayer(BasePlayer): class MPCHCAPIPlayer(BasePlayer):
speedSupported = False speedSupported = False
alertOSDSupported = False alertOSDSupported = False
@ -407,10 +400,7 @@ class MPCHCAPIPlayer(BasePlayer):
def openFile(self, filePath, resetPosition=False): def openFile(self, filePath, resetPosition=False):
self._mpcApi.openFile(filePath) self._mpcApi.openFile(filePath)
def displayMessage( def displayMessage(self, message, duration = (constants.OSD_DURATION*1000), OSDType=constants.OSD_NOTIFICATION, mood=constants.MESSAGE_NEUTRAL):
self, message,
duration=(constants.OSD_DURATION*1000), OSDType=constants.OSD_NOTIFICATION, mood=constants.MESSAGE_NEUTRAL
):
self._mpcApi.sendOsd(message, constants.MPC_OSD_POSITION, duration) self._mpcApi.sendOsd(message, constants.MPC_OSD_POSITION, duration)
@retry(MpcHcApi.PlayerNotReadyException, constants.MPC_MAX_RETRIES, constants.MPC_RETRY_WAIT_TIME, 1) @retry(MpcHcApi.PlayerNotReadyException, constants.MPC_MAX_RETRIES, constants.MPC_RETRY_WAIT_TIME, 1)
@ -422,7 +412,6 @@ class MPCHCAPIPlayer(BasePlayer):
self._mpcApi.pause() self._mpcApi.pause()
else: else:
self._mpcApi.unpause() self._mpcApi.unpause()
def setFeatures(self, featureList): def setFeatures(self, featureList):
pass pass
@ -493,10 +482,7 @@ class MPCHCAPIPlayer(BasePlayer):
@staticmethod @staticmethod
def getIconPath(path): def getIconPath(path):
if ( if MPCHCAPIPlayer.getExpandedPath(path).lower().endswith('mpc-hc64.exe'.lower()) or MPCHCAPIPlayer.getExpandedPath(path).lower().endswith('mpc-hc64_nvo.exe'.lower()):
MPCHCAPIPlayer.getExpandedPath(path).lower().endswith('mpc-hc64.exe'.lower()) or
MPCHCAPIPlayer.getExpandedPath(path).lower().endswith('mpc-hc64_nvo.exe'.lower())
):
return constants.MPC64_ICONPATH return constants.MPC64_ICONPATH
else: else:
return constants.MPC_ICONPATH return constants.MPC_ICONPATH
@ -510,11 +496,7 @@ class MPCHCAPIPlayer(BasePlayer):
@staticmethod @staticmethod
def getExpandedPath(path): def getExpandedPath(path):
if os.path.isfile(path): if os.path.isfile(path):
if ( if path.lower().endswith('mpc-hc.exe'.lower()) or path.lower().endswith('mpc-hcportable.exe'.lower()) or path.lower().endswith('mpc-hc64.exe'.lower()) or path.lower().endswith('mpc-hc64_nvo.exe'.lower()) or path.lower().endswith('mpc-hc_nvo.exe'.lower()):
path.lower().endswith('mpc-hc.exe'.lower()) or path.lower().endswith('mpc-hcportable.exe'.lower()) or
path.lower().endswith('mpc-hc64.exe'.lower()) or path.lower().endswith('mpc-hc64_nvo.exe'.lower()) or
path.lower().endswith('mpc-hc_nvo.exe'.lower())
):
return path return path
if os.path.isfile(path + "mpc-hc.exe"): if os.path.isfile(path + "mpc-hc.exe"):
path += "mpc-hc.exe" path += "mpc-hc.exe"
@ -546,3 +528,4 @@ class MPCHCAPIPlayer(BasePlayer):
if os.path.isfile(path + "\\mpc-hc64_nvo.exe"): if os.path.isfile(path + "\\mpc-hc64_nvo.exe"):
path += "\\mpc-hc64_nvo.exe" path += "\\mpc-hc64_nvo.exe"
return path return path

View File

@ -1,11 +1,8 @@
import os.path
from syncplay import constants from syncplay import constants
import os.path
from syncplay.messages import getMessage from syncplay.messages import getMessage
from syncplay.players.mpc import MPCHCAPIPlayer from syncplay.players.mpc import MPCHCAPIPlayer
class MpcBePlayer(MPCHCAPIPlayer): class MpcBePlayer(MPCHCAPIPlayer):
@staticmethod @staticmethod
def run(client, playerPath, filePath, args): def run(client, playerPath, filePath, args):
@ -33,11 +30,7 @@ class MpcBePlayer(MPCHCAPIPlayer):
@staticmethod @staticmethod
def getExpandedPath(path): def getExpandedPath(path):
if os.path.isfile(path): if os.path.isfile(path):
if ( if path.lower().endswith('mpc-be.exe'.lower()) or path.lower().endswith('mpc-be64.exe'.lower() or path.lower().endswith('mpc-beportable.exe'.lower())):
path.lower().endswith('mpc-be.exe'.lower()) or
path.lower().endswith('mpc-be64.exe'.lower()) or
path.lower().endswith('mpc-beportable.exe'.lower())
):
return path return path
if os.path.isfile(path + "mpc-be.exe"): if os.path.isfile(path + "mpc-be.exe"):
path += "mpc-be.exe" path += "mpc-be.exe"

View File

@ -1,18 +1,14 @@
# coding:utf8 # coding:utf8
import os
import re
import subprocess import subprocess
import sys import re
import threading import threading
import time import time
from syncplay import constants, utils
from syncplay.players.basePlayer import BasePlayer from syncplay.players.basePlayer import BasePlayer
from syncplay import constants, utils
from syncplay.messages import getMessage from syncplay.messages import getMessage
import os, sys
from syncplay.utils import isWindows from syncplay.utils import isWindows
class MplayerPlayer(BasePlayer): class MplayerPlayer(BasePlayer):
speedSupported = True speedSupported = True
customOpenDialog = False customOpenDialog = False
@ -94,20 +90,15 @@ class MplayerPlayer(BasePlayer):
def _getProperty(self, property_): def _getProperty(self, property_):
self._listener.sendLine("get_property {}".format(property_)) self._listener.sendLine("get_property {}".format(property_))
def displayMessage( def displayMessage(self, message, duration=(constants.OSD_DURATION * 1000), OSDType=constants.OSD_NOTIFICATION, mood=constants.MESSAGE_NEUTRAL):
self, message,
duration=(constants.OSD_DURATION * 1000), OSDType=constants.OSD_NOTIFICATION, mood=constants.MESSAGE_NEUTRAL
):
messageString = self._sanitizeText(message.replace("\\n", "<NEWLINE>")).replace("<NEWLINE>", "\\n") messageString = self._sanitizeText(message.replace("\\n", "<NEWLINE>")).replace("<NEWLINE>", "\\n")
self._listener.sendLine('{} "{!s}" {} {}'.format( self._listener.sendLine('{} "{!s}" {} {}'.format(self.OSD_QUERY, messageString, duration, constants.MPLAYER_OSD_LEVEL))
self.OSD_QUERY, messageString, duration, constants.MPLAYER_OSD_LEVEL))
def displayChatMessage(self, username, message): def displayChatMessage(self, username, message):
messageString = "<{}> {}".format(username, message) messageString = "<{}> {}".format(username, message)
messageString = self._sanitizeText(messageString.replace("\\n", "<NEWLINE>")).replace("<NEWLINE>", "\\n") messageString = self._sanitizeText(messageString.replace("\\n", "<NEWLINE>")).replace("<NEWLINE>", "\\n")
duration = int(constants.OSD_DURATION * 1000) duration = int(constants.OSD_DURATION * 1000)
self._listener.sendLine('{} "{!s}" {} {}'.format( self._listener.sendLine('{} "{!s}" {} {}'.format(self.OSD_QUERY, messageString, duration, constants.MPLAYER_OSD_LEVEL))
self.OSD_QUERY, messageString, duration, constants.MPLAYER_OSD_LEVEL))
def setSpeed(self, value): def setSpeed(self, value):
self._setProperty('speed', "{:.2f}".format(value)) self._setProperty('speed', "{:.2f}".format(value))
@ -190,13 +181,7 @@ class MplayerPlayer(BasePlayer):
line = line.replace("[term-msg] ", "") # -v workaround line = line.replace("[term-msg] ", "") # -v workaround
line = line.replace(" cplayer: ","") # --msg-module workaround line = line.replace(" cplayer: ","") # --msg-module workaround
line = line.replace(" term-msg: ", "") line = line.replace(" term-msg: ", "")
if ( if "Failed to get value of property" in line or "=(unavailable)" in line or line == "ANS_filename=" or line == "ANS_length=" or line == "ANS_path=":
"Failed to get value of property" in line or
"=(unavailable)" in line or
line == "ANS_filename=" or
line == "ANS_length=" or
line == "ANS_path="
):
if "filename" in line: if "filename" in line:
self._getFilename() self._getFilename()
elif "length" in line: elif "length" in line:
@ -265,7 +250,7 @@ class MplayerPlayer(BasePlayer):
@staticmethod @staticmethod
def isValidPlayerPath(path): def isValidPlayerPath(path):
if "mplayer" in path and MplayerPlayer.getExpandedPath(path) and "mplayerc.exe" not in path: # "mplayerc.exe" is Media Player Classic (not Home Cinema): if "mplayer" in path and MplayerPlayer.getExpandedPath(path) and not "mplayerc.exe" in path: # "mplayerc.exe" is Media Player Classic (not Home Cinema):
return True return True
return False return False
@ -339,15 +324,12 @@ class MplayerPlayer(BasePlayer):
if 'TERM' in env: if 'TERM' in env:
del env['TERM'] del env['TERM']
if filePath: if filePath:
self.__process = subprocess.Popen( self.__process = subprocess.Popen(call, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=self.__getCwd(filePath, env), env=env, bufsize=0)
call, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT,
cwd=self.__getCwd(filePath, env), env=env, bufsize=0)
else: else:
self.__process = subprocess.Popen( self.__process = subprocess.Popen(call, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT, env=env, bufsize=0)
call, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT,
env=env, bufsize=0)
threading.Thread.__init__(self, name="MPlayer Listener") threading.Thread.__init__(self, name="MPlayer Listener")
def __getCwd(self, filePath, env): def __getCwd(self, filePath, env):
if not filePath: if not filePath:
return None return None
@ -383,8 +365,8 @@ class MplayerPlayer(BasePlayer):
if command and command[:1] == "/": if command and command[:1] == "/":
message = message[1:] message = message[1:]
else: else:
self.__playerController.reactor.callFromThread( self.__playerController.reactor.callFromThread(self.__playerController._client.ui.executeCommand,
self.__playerController._client.ui.executeCommand, command) command)
return return
self.__playerController.reactor.callFromThread(self.__playerController._client.sendChat, message) self.__playerController.reactor.callFromThread(self.__playerController._client.sendChat, message)
@ -396,11 +378,11 @@ class MplayerPlayer(BasePlayer):
oldState = self.readyToSend oldState = self.readyToSend
self.readyToSend = newReadyState self.readyToSend = newReadyState
self.lastNotReadyTime = time.time() if newReadyState == False else None self.lastNotReadyTime = time.time() if newReadyState == False else None
if self.readyToSend: if self.readyToSend == True:
self.__playerController._client.ui.showDebugMessage("<mpv> Ready to send: True") self.__playerController._client.ui.showDebugMessage("<mpv> Ready to send: True")
else: else:
self.__playerController._client.ui.showDebugMessage("<mpv> Ready to send: False") self.__playerController._client.ui.showDebugMessage("<mpv> Ready to send: False")
if self.readyToSend and oldState == False: if self.readyToSend == True and oldState == False:
self.processSendQueue() self.processSendQueue()
def checkForReadinessOverride(self): def checkForReadinessOverride(self):
@ -409,7 +391,7 @@ class MplayerPlayer(BasePlayer):
def sendLine(self, line, notReadyAfterThis=None): def sendLine(self, line, notReadyAfterThis=None):
self.checkForReadinessOverride() self.checkForReadinessOverride()
if not self.readyToSend and "print_text ANS_pause" in line: if self.readyToSend == False and "print_text ANS_pause" in line:
self.__playerController._client.ui.showDebugMessage("<mpv> Not ready to get status update, so skipping") self.__playerController._client.ui.showDebugMessage("<mpv> Not ready to get status update, so skipping")
return return
try: try:
@ -419,13 +401,11 @@ class MplayerPlayer(BasePlayer):
if line.startswith(command): if line.startswith(command):
for itemID, deletionCandidate in enumerate(self.sendQueue): for itemID, deletionCandidate in enumerate(self.sendQueue):
if deletionCandidate.startswith(command): if deletionCandidate.startswith(command):
self.__playerController._client.ui.showDebugMessage( self.__playerController._client.ui.showDebugMessage("<mpv> Remove duplicate (supersede): {}".format(self.sendQueue[itemID]))
"<mpv> Remove duplicate (supersede): {}".format(self.sendQueue[itemID]))
try: try:
self.sendQueue.remove(self.sendQueue[itemID]) self.sendQueue.remove(self.sendQueue[itemID])
except UnicodeWarning: except UnicodeWarning:
self.__playerController._client.ui.showDebugMessage( self.__playerController._client.ui.showDebugMessage("<mpv> Unicode mismatch occured when trying to remove duplicate")
"<mpv> Unicode mismatch occured when trying to remove duplicate")
# TODO: Prevent this from being triggered # TODO: Prevent this from being triggered
pass pass
break break
@ -435,8 +415,7 @@ class MplayerPlayer(BasePlayer):
if line == command: if line == command:
for itemID, deletionCandidate in enumerate(self.sendQueue): for itemID, deletionCandidate in enumerate(self.sendQueue):
if deletionCandidate == command: if deletionCandidate == command:
self.__playerController._client.ui.showDebugMessage( self.__playerController._client.ui.showDebugMessage("<mpv> Remove duplicate (delete both): {}".format(self.sendQueue[itemID]))
"<mpv> Remove duplicate (delete both): {}".format(self.sendQueue[itemID]))
self.__playerController._client.ui.showDebugMessage(self.sendQueue[itemID]) self.__playerController._client.ui.showDebugMessage(self.sendQueue[itemID])
return return
except: except:
@ -449,9 +428,7 @@ class MplayerPlayer(BasePlayer):
def processSendQueue(self): def processSendQueue(self):
while self.sendQueue and self.readyToSend: while self.sendQueue and self.readyToSend:
if self.lastSendTime and time.time() - self.lastSendTime < constants.MPV_SENDMESSAGE_COOLDOWN_TIME: if self.lastSendTime and time.time() - self.lastSendTime < constants.MPV_SENDMESSAGE_COOLDOWN_TIME:
self.__playerController._client.ui.showDebugMessage( self.__playerController._client.ui.showDebugMessage("<mpv> Throttling message send, so sleeping for {}".format(constants.MPV_SENDMESSAGE_COOLDOWN_TIME))
"<mpv> Throttling message send, so sleeping for {}".format(
constants.MPV_SENDMESSAGE_COOLDOWN_TIME))
time.sleep(constants.MPV_SENDMESSAGE_COOLDOWN_TIME) time.sleep(constants.MPV_SENDMESSAGE_COOLDOWN_TIME)
try: try:
lineToSend = self.sendQueue.pop() lineToSend = self.sendQueue.pop()

View File

@ -1,18 +1,14 @@
# coding:utf8 # coding:utf8
import os
import re import re
import sys
import time
import subprocess import subprocess
from syncplay import constants
from syncplay.players.mplayer import MplayerPlayer from syncplay.players.mplayer import MplayerPlayer
from syncplay.messages import getMessage from syncplay.messages import getMessage
from syncplay import constants
from syncplay.utils import isURL, findResourcePath from syncplay.utils import isURL, findResourcePath
import os, sys, time
class MpvPlayer(MplayerPlayer): class MpvPlayer(MplayerPlayer):
RE_VERSION = re.compile(r'.*mpv (\d+)\.(\d+)\.\d+.*') RE_VERSION = re.compile('.*mpv (\d+)\.(\d+)\.\d+.*')
osdMessageSeparator = "\\n" osdMessageSeparator = "\\n"
osdMessageSeparator = "; " # TODO: Make conditional osdMessageSeparator = "; " # TODO: Make conditional
@ -25,9 +21,7 @@ class MpvPlayer(MplayerPlayer):
constants.MPV_NEW_VERSION = ver is None or int(ver.group(1)) > 0 or int(ver.group(2)) >= 6 constants.MPV_NEW_VERSION = ver is None or int(ver.group(1)) > 0 or int(ver.group(2)) >= 6
constants.MPV_OSC_VISIBILITY_CHANGE_VERSION = False if ver is None else int(ver.group(1)) > 0 or int(ver.group(2)) >= 28 constants.MPV_OSC_VISIBILITY_CHANGE_VERSION = False if ver is None else int(ver.group(1)) > 0 or int(ver.group(2)) >= 28
if not constants.MPV_OSC_VISIBILITY_CHANGE_VERSION: if not constants.MPV_OSC_VISIBILITY_CHANGE_VERSION:
client.ui.showDebugMessage( client.ui.showDebugMessage("This version of mpv is not known to be compatible with changing the OSC visibility. Please use mpv >=0.28.0.")
"This version of mpv is not known to be compatible with changing the OSC visibility. "
"Please use mpv >=0.28.0.")
if constants.MPV_NEW_VERSION: if constants.MPV_NEW_VERSION:
return NewMpvPlayer(client, MpvPlayer.getExpandedPath(playerPath), filePath, args) return NewMpvPlayer(client, MpvPlayer.getExpandedPath(playerPath), filePath, args)
else: else:
@ -83,7 +77,6 @@ class MpvPlayer(MplayerPlayer):
def getPlayerPathErrors(playerPath, filePath): def getPlayerPathErrors(playerPath, filePath):
return None return None
class OldMpvPlayer(MpvPlayer): class OldMpvPlayer(MpvPlayer):
POSITION_QUERY = 'time-pos' POSITION_QUERY = 'time-pos'
OSD_QUERY = 'show_text' OSD_QUERY = 'show_text'
@ -118,7 +111,6 @@ class OldMpvPlayer(MpvPlayer):
self.setPaused(self._client.getGlobalPaused()) self.setPaused(self._client.getGlobalPaused())
self.setPosition(self._client.getGlobalPosition()) self.setPosition(self._client.getGlobalPosition())
class NewMpvPlayer(OldMpvPlayer): class NewMpvPlayer(OldMpvPlayer):
lastResetTime = None lastResetTime = None
lastMPVPositionUpdate = None lastMPVPositionUpdate = None
@ -130,15 +122,14 @@ class NewMpvPlayer(OldMpvPlayer):
if not self._client._config["chatOutputEnabled"]: if not self._client._config["chatOutputEnabled"]:
super(self.__class__, self).displayMessage(message=message,duration=duration,OSDType=OSDType,mood=mood) super(self.__class__, self).displayMessage(message=message,duration=duration,OSDType=OSDType,mood=mood)
return return
messageString = self._sanitizeText(message.replace("\\n", "<NEWLINE>")).replace( messageString = self._sanitizeText(message.replace("\\n", "<NEWLINE>")).replace("\\\\",constants.MPV_INPUT_BACKSLASH_SUBSTITUTE_CHARACTER).replace("<NEWLINE>", "\\n")
"\\\\", constants.MPV_INPUT_BACKSLASH_SUBSTITUTE_CHARACTER).replace("<NEWLINE>", "\\n")
self._listener.sendLine('script-message-to syncplayintf {}-osd-{} "{}"'.format(OSDType, mood, messageString)) self._listener.sendLine('script-message-to syncplayintf {}-osd-{} "{}"'.format(OSDType, mood, messageString))
def displayChatMessage(self, username, message): def displayChatMessage(self, username, message):
if not self._client._config["chatOutputEnabled"]: if not self._client._config["chatOutputEnabled"]:
super(self.__class__, self).displayChatMessage(username,message) super(self.__class__, self).displayChatMessage(username,message)
return return
username = self._sanitizeText(username.replace("\\", sconstants.MPV_INPUT_BACKSLASH_SUBSTITUTE_CHARACTER)) username = self._sanitizeText(username.replace("\\",constants.MPV_INPUT_BACKSLASH_SUBSTITUTE_CHARACTER))
message = self._sanitizeText(message.replace("\\",constants.MPV_INPUT_BACKSLASH_SUBSTITUTE_CHARACTER)) message = self._sanitizeText(message.replace("\\",constants.MPV_INPUT_BACKSLASH_SUBSTITUTE_CHARACTER))
messageString = "<{}> {}".format(username, message) messageString = "<{}> {}".format(username, message)
self._listener.sendLine('script-message-to syncplayintf chat "{}"'.format(messageString)) self._listener.sendLine('script-message-to syncplayintf chat "{}"'.format(messageString))
@ -164,34 +155,25 @@ class NewMpvPlayer(OldMpvPlayer):
self._listener.sendLine("print_text ""ANS_{}=${{{}}}""".format(property_, propertyID)) self._listener.sendLine("print_text ""ANS_{}=${{{}}}""".format(property_, propertyID))
def getCalculatedPosition(self): def getCalculatedPosition(self):
if not self.fileLoaded: if self.fileLoaded == False:
self._client.ui.showDebugMessage( self._client.ui.showDebugMessage("File not loaded so using GlobalPosition for getCalculatedPosition({})".format(self._client.getGlobalPosition()))
"File not loaded so using GlobalPosition for getCalculatedPosition({})".format(
self._client.getGlobalPosition()))
return self._client.getGlobalPosition() return self._client.getGlobalPosition()
if self.lastMPVPositionUpdate is None: if self.lastMPVPositionUpdate is None:
self._client.ui.showDebugMessage( self._client.ui.showDebugMessage("MPV not updated position so using GlobalPosition for getCalculatedPosition ({})".format(self._client.getGlobalPosition()))
"MPV not updated position so using GlobalPosition for getCalculatedPosition ({})".format(
self._client.getGlobalPosition()))
return self._client.getGlobalPosition() return self._client.getGlobalPosition()
if self._recentlyReset(): if self._recentlyReset():
self._client.ui.showDebugMessage( self._client.ui.showDebugMessage("Recently reset so using self.position for getCalculatedPosition ({})".format(self._position))
"Recently reset so using self.position for getCalculatedPosition ({})".format(
self._position))
return self._position return self._position
diff = time.time() - self.lastMPVPositionUpdate diff = time.time() - self.lastMPVPositionUpdate
if diff > constants.MPV_UNRESPONSIVE_THRESHOLD: if diff > constants.MPV_UNRESPONSIVE_THRESHOLD:
self.reactor.callFromThread( self.reactor.callFromThread(self._client.ui.showErrorMessage, getMessage("mpv-unresponsive-error").format(int(diff)), True)
self._client.ui.showErrorMessage, getMessage("mpv-unresponsive-error").format(int(diff)), True)
self.drop() self.drop()
if diff > constants.PLAYER_ASK_DELAY and not self._paused: if diff > constants.PLAYER_ASK_DELAY and not self._paused:
self._client.ui.showDebugMessage( self._client.ui.showDebugMessage("mpv did not response in time, so assuming position is {} ({}+{})".format(self._position + diff, self._position, diff))
"mpv did not response in time, so assuming position is {} ({}+{})".format(
self._position + diff, self._position, diff))
return self._position + diff return self._position + diff
else: else:
return self._position return self._position
@ -204,8 +186,7 @@ class NewMpvPlayer(OldMpvPlayer):
elif self._fileIsLoaded() or (value < constants.MPV_NEWFILE_IGNORE_TIME and self._fileIsLoaded(ignoreDelay=True)): elif self._fileIsLoaded() or (value < constants.MPV_NEWFILE_IGNORE_TIME and self._fileIsLoaded(ignoreDelay=True)):
self._position = max(value,0) self._position = max(value,0)
else: else:
self._client.ui.showDebugMessage( self._client.ui.showDebugMessage("No file loaded so storing position as GlobalPosition ({})".format(self._client.getGlobalPosition()))
"No file loaded so storing position as GlobalPosition ({})".format(self._client.getGlobalPosition()))
self._position = self._client.getGlobalPosition() self._position = self._client.getGlobalPosition()
def _storePauseState(self, value): def _storePauseState(self, value):
@ -224,8 +205,7 @@ class NewMpvPlayer(OldMpvPlayer):
self._getPausedAndPosition() self._getPausedAndPosition()
self._positionAsk.wait(constants.MPV_LOCK_WAIT_TIME) self._positionAsk.wait(constants.MPV_LOCK_WAIT_TIME)
self._pausedAsk.wait(constants.MPV_LOCK_WAIT_TIME) self._pausedAsk.wait(constants.MPV_LOCK_WAIT_TIME)
self._client.updatePlayerStatus( self._client.updatePlayerStatus(self._paused if self.fileLoaded else self._client.getGlobalPaused(), self.getCalculatedPosition())
self._paused if self.fileLoaded else self._client.getGlobalPaused(), self.getCalculatedPosition())
def _getPausedAndPosition(self): def _getPausedAndPosition(self):
self._listener.sendLine("print_text ANS_pause=${pause}\r\nprint_text ANS_time-pos=${=time-pos}") self._listener.sendLine("print_text ANS_pause=${pause}\r\nprint_text ANS_time-pos=${=time-pos}")
@ -249,8 +229,7 @@ class NewMpvPlayer(OldMpvPlayer):
def setPosition(self, value): def setPosition(self, value):
if value < constants.DO_NOT_RESET_POSITION_THRESHOLD and self._recentlyReset(): if value < constants.DO_NOT_RESET_POSITION_THRESHOLD and self._recentlyReset():
self._client.ui.showDebugMessage( self._client.ui.showDebugMessage("Did not seek as recently reset and {} below 'do not reset position' threshold".format(value))
"Did not seek as recently reset and {} below 'do not reset position' threshold".format(value))
return return
super(self.__class__, self).setPosition(value) super(self.__class__, self).setPosition(value)
self.lastMPVPositionUpdate = time.time() self.lastMPVPositionUpdate = time.time()
@ -266,7 +245,7 @@ class NewMpvPlayer(OldMpvPlayer):
self._client.ui.showDebugMessage("Want to set paused to {}".format(self._client.getGlobalPaused())) self._client.ui.showDebugMessage("Want to set paused to {}".format(self._client.getGlobalPaused()))
else: else:
self._client.ui.showDebugMessage("Don't want to set paused to {}".format(self._client.getGlobalPaused())) self._client.ui.showDebugMessage("Don't want to set paused to {}".format(self._client.getGlobalPaused()))
if not resetPosition: if resetPosition == False:
self.setPosition(self._client.getGlobalPosition()) self.setPosition(self._client.getGlobalPosition())
else: else:
self._storePosition(0) self._storePosition(0)
@ -306,14 +285,7 @@ class NewMpvPlayer(OldMpvPlayer):
self._listener.setReadyToSend(True) self._listener.setReadyToSend(True)
def _setOSDPosition(self): def _setOSDPosition(self):
if ( if self._client._config['chatMoveOSD'] and (self._client._config['chatOutputEnabled'] or (self._client._config['chatInputEnabled'] and self._client._config['chatInputPosition'] == constants.INPUT_POSITION_TOP)):
self._client._config['chatMoveOSD'] and (
self._client._config['chatOutputEnabled'] or (
self._client._config['chatInputEnabled'] and
self._client._config['chatInputPosition'] == constants.INPUT_POSITION_TOP
)
)
):
self._setProperty("osd-align-y", "bottom") self._setProperty("osd-align-y", "bottom")
self._setProperty("osd-margin-y", int(self._client._config['chatOSDMargin'])) self._setProperty("osd-margin-y", int(self._client._config['chatOSDMargin']))
@ -337,9 +309,9 @@ class NewMpvPlayer(OldMpvPlayer):
def _fileIsLoaded(self, ignoreDelay=False): def _fileIsLoaded(self, ignoreDelay=False):
if ignoreDelay: if ignoreDelay:
self._client.ui.showDebugMessage("Ignoring _fileIsLoaded MPV_NEWFILE delay") self._client.ui.showDebugMessage("Ignoring _fileIsLoaded MPV_NEWFILE delay")
return bool(self.fileLoaded) return True if self.fileLoaded else False
return ( if self.fileLoaded == True and self.lastLoadedTime != None and time.time() > (self.lastLoadedTime + constants.MPV_NEWFILE_IGNORE_TIME):
self.fileLoaded and self.lastLoadedTime is not None and return True
time.time() > (self.lastLoadedTime + constants.MPV_NEWFILE_IGNORE_TIME) else:
) return False

View File

@ -1,6 +1,5 @@
import syncplay.players import syncplay.players
class PlayerFactory(object): class PlayerFactory(object):
def __init__(self): def __init__(self):
self._players = syncplay.players.getAvailablePlayers() self._players = syncplay.players.getAvailablePlayers()

View File

@ -1,24 +1,18 @@
import asynchat
import asyncore
import os
import random
import re
import socket
import subprocess import subprocess
import sys import re
import threading import threading
import time
import urllib.error
import urllib.parse
import urllib.request
from syncplay import constants, utils
from syncplay.messages import getMessage
from syncplay.players.basePlayer import BasePlayer from syncplay.players.basePlayer import BasePlayer
from syncplay import constants, utils
import os
import sys
import random
import socket
import asynchat, asyncore
import urllib.request, urllib.parse, urllib.error
import time
from syncplay.messages import getMessage
from syncplay.utils import isBSD, isLinux, isWindows, isMacOS from syncplay.utils import isBSD, isLinux, isWindows, isMacOS
class VlcPlayer(BasePlayer): class VlcPlayer(BasePlayer):
speedSupported = True speedSupported = True
customOpenDialog = False customOpenDialog = False
@ -53,8 +47,7 @@ class VlcPlayer(BasePlayer):
if self.radixChar == "" or self.radixChar == "1" or self.radixChar == "5": if self.radixChar == "" or self.radixChar == "1" or self.radixChar == "5":
raise ValueError raise ValueError
except: except:
self._client.ui.showErrorMessage( self._client.ui.showErrorMessage("Failed to determine locale. As a fallback Syncplay is using the following radix character: \".\".")
"Failed to determine locale. As a fallback Syncplay is using the following radix character: \".\".")
self.radixChar = "." self.radixChar = "."
self._durationAsk = threading.Event() self._durationAsk = threading.Event()
@ -117,8 +110,7 @@ class VlcPlayer(BasePlayer):
return self._client.getGlobalPosition() return self._client.getGlobalPosition()
diff = time.time() - self._lastVLCPositionUpdate diff = time.time() - self._lastVLCPositionUpdate
if diff > constants.PLAYER_ASK_DELAY and not self._paused: if diff > constants.PLAYER_ASK_DELAY and not self._paused:
self._client.ui.showDebugMessage("VLC did not response in time, so assuming position is {} ({}+{})".format( self._client.ui.showDebugMessage("VLC did not response in time, so assuming position is {} ({}+{})".format(self._position + diff, self._position, diff))
self._position + diff, self._position, diff))
if diff > constants.VLC_LATENCY_ERROR_THRESHOLD: if diff > constants.VLC_LATENCY_ERROR_THRESHOLD:
if not self.shownVLCLatencyError or constants.DEBUG_MODE: if not self.shownVLCLatencyError or constants.DEBUG_MODE:
self._client.ui.showErrorMessage(getMessage("media-player-latency-warning").format(int(diff))) self._client.ui.showErrorMessage(getMessage("media-player-latency-warning").format(int(diff)))
@ -127,10 +119,7 @@ class VlcPlayer(BasePlayer):
else: else:
return self._position return self._position
def displayMessage( def displayMessage(self, message, duration=constants.OSD_DURATION * 1000, OSDType=constants.OSD_DURATION, mood=constants.MESSAGE_NEUTRAL):
self, message,
duration=constants.OSD_DURATION * 1000, OSDType=constants.OSD_DURATION, mood=constants.MESSAGE_NEUTRAL
):
duration /= 1000 duration /= 1000
if OSDType != constants.OSD_ALERT: if OSDType != constants.OSD_ALERT:
self._listener.sendLine('display-osd: {}, {}, {}'.format('top-right', duration, message)) self._listener.sendLine('display-osd: {}, {}, {}'.format('top-right', duration, message))
@ -223,25 +212,21 @@ class VlcPlayer(BasePlayer):
self._duration = float(value.replace(",", ".")) self._duration = float(value.replace(",", "."))
self._durationAsk.set() self._durationAsk.set()
elif name == "playstate": elif name == "playstate":
self._paused = bool(value != 'playing') if (value != "no-input" and not self._filechanged) else self._client.getGlobalPaused() self._paused = bool(value != 'playing') if(value != "no-input" and self._filechanged == False) else self._client.getGlobalPaused()
diff = time.time() - self._lastVLCPositionUpdate if self._lastVLCPositionUpdate else 0 diff = time.time() - self._lastVLCPositionUpdate if self._lastVLCPositionUpdate else 0
if ( if self._paused == False \
self._paused == False and and self._position == self._previousPreviousPosition \
self._position == self._previousPreviousPosition and and self._previousPosition == self._position \
self._previousPosition == self._position and and self._duration > constants.PLAYLIST_LOAD_NEXT_FILE_MINIMUM_LENGTH \
self._duration > constants.PLAYLIST_LOAD_NEXT_FILE_MINIMUM_LENGTH and and (self._duration - self._position) < constants.VLC_EOF_DURATION_THRESHOLD \
(self._duration - self._position) < constants.VLC_EOF_DURATION_THRESHOLD and and diff > constants.VLC_LATENCY_ERROR_THRESHOLD:
diff > constants.VLC_LATENCY_ERROR_THRESHOLD
):
self._client.ui.showDebugMessage("Treating 'playing' response as 'paused' due to VLC EOF bug") self._client.ui.showDebugMessage("Treating 'playing' response as 'paused' due to VLC EOF bug")
self.setPaused(True) self.setPaused(True)
self._pausedAsk.set() self._pausedAsk.set()
elif name == "position": elif name == "position":
newPosition = float(value.replace(",", ".")) if (value != "no-input" and not self._filechanged) else self._client.getGlobalPosition() newPosition = float(value.replace(",", ".")) if (value != "no-input" and self._filechanged == False) else self._client.getGlobalPosition()
if newPosition == self._previousPosition and newPosition != self._duration and self._paused is False: if newPosition == self._previousPosition and newPosition != self._duration and not self._paused:
self._client.ui.showDebugMessage( self._client.ui.showDebugMessage("Not considering position {} duplicate as new time because of VLC time precision bug".format(newPosition))
"Not considering position {} duplicate as new time because of VLC time precision bug".format(
newPosition))
self._previousPreviousPosition = self._previousPosition self._previousPreviousPosition = self._previousPosition
self._previousPosition = self._position self._previousPosition = self._position
self._positionAsk.set() self._positionAsk.set()
@ -341,7 +326,6 @@ class VlcPlayer(BasePlayer):
call.append(filePath) call.append(filePath)
else: else:
call.append(self.__playerController.getMRL(filePath)) call.append(self.__playerController.getMRL(filePath))
def _usevlcintf(vlcIntfPath, vlcIntfUserPath): def _usevlcintf(vlcIntfPath, vlcIntfUserPath):
vlcSyncplayInterfacePath = vlcIntfPath + "syncplay.lua" vlcSyncplayInterfacePath = vlcIntfPath + "syncplay.lua"
if not os.path.isfile(vlcSyncplayInterfacePath): if not os.path.isfile(vlcSyncplayInterfacePath):
@ -363,8 +347,7 @@ class VlcPlayer(BasePlayer):
playerController.vlcIntfUserPath = os.path.join(os.getenv('HOME', '.'), ".local/share/vlc/lua/intf/") playerController.vlcIntfUserPath = os.path.join(os.getenv('HOME', '.'), ".local/share/vlc/lua/intf/")
elif isMacOS(): elif isMacOS():
playerController.vlcIntfPath = "/Applications/VLC.app/Contents/MacOS/share/lua/intf/" playerController.vlcIntfPath = "/Applications/VLC.app/Contents/MacOS/share/lua/intf/"
playerController.vlcIntfUserPath = os.path.join( playerController.vlcIntfUserPath = os.path.join(os.getenv('HOME', '.'), "Library/Application Support/org.videolan.vlc/lua/intf/")
os.getenv('HOME', '.'), "Library/Application Support/org.videolan.vlc/lua/intf/")
elif isBSD(): elif isBSD():
# *BSD ports/pkgs install to /usr/local by default. # *BSD ports/pkgs install to /usr/local by default.
# This should also work for all the other BSDs, such as OpenBSD or DragonFly. # This should also work for all the other BSDs, such as OpenBSD or DragonFly.
@ -375,17 +358,14 @@ class VlcPlayer(BasePlayer):
playerController.vlcIntfUserPath = os.path.join(os.getenv('APPDATA', '.'), "VLC\\lua\\intf\\") playerController.vlcIntfUserPath = os.path.join(os.getenv('APPDATA', '.'), "VLC\\lua\\intf\\")
playerController.vlcModulePath = playerController.vlcIntfPath + "modules/?.luac" playerController.vlcModulePath = playerController.vlcIntfPath + "modules/?.luac"
if _usevlcintf(playerController.vlcIntfPath, playerController.vlcIntfUserPath): if _usevlcintf(playerController.vlcIntfPath, playerController.vlcIntfUserPath):
playerController.SLAVE_ARGS.append( playerController.SLAVE_ARGS.append('--lua-config=syncplay={{port=\"{}\"}}'.format(str(playerController.vlcport)))
'--lua-config=syncplay={{port=\"{}\"}}'.format(str(playerController.vlcport)))
else: else:
if isLinux(): if isLinux():
playerController.vlcDataPath = "/usr/lib/syncplay/resources" playerController.vlcDataPath = "/usr/lib/syncplay/resources"
else: else:
playerController.vlcDataPath = utils.findWorkingDir() + "\\resources" playerController.vlcDataPath = utils.findWorkingDir() + "\\resources"
playerController.SLAVE_ARGS.append('--data-path={}'.format(playerController.vlcDataPath)) playerController.SLAVE_ARGS.append('--data-path={}'.format(playerController.vlcDataPath))
playerController.SLAVE_ARGS.append( playerController.SLAVE_ARGS.append('--lua-config=syncplay={{modulepath=\"{}\",port=\"{}\"}}'.format(playerController.vlcModulePath, str(playerController.vlcport)))
'--lua-config=syncplay={{modulepath=\"{}\",port=\"{}\"}}'.format(
playerController.vlcModulePath, str(playerController.vlcport)))
call.extend(playerController.SLAVE_ARGS) call.extend(playerController.SLAVE_ARGS)
if args: if args:
@ -396,15 +376,11 @@ class VlcPlayer(BasePlayer):
self._vlcVersion = None self._vlcVersion = None
if self.oldIntfVersion: if self.oldIntfVersion:
self.__playerController.drop( self.__playerController.drop(getMessage("vlc-interface-version-mismatch").format(self.oldIntfVersion,constants.VLC_INTERFACE_MIN_VERSION))
getMessage("vlc-interface-version-mismatch").format(
self.oldIntfVersion, constants.VLC_INTERFACE_MIN_VERSION))
else: else:
if isWindows() and getattr(sys, 'frozen', '') and getattr(sys, '_MEIPASS', '') is not None: #Needed for pyinstaller --onefile bundle if isWindows() and getattr(sys, 'frozen', '') and getattr(sys, '_MEIPASS', '') is not None: #Needed for pyinstaller --onefile bundle
self.__process = subprocess.Popen( self.__process = subprocess.Popen(call, stdin=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE, shell=False, creationflags=0x08000000)
call, stdin=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE,
shell=False, creationflags=0x08000000)
else: else:
self.__process = subprocess.Popen(call, stderr=subprocess.PIPE, stdout=subprocess.PIPE) self.__process = subprocess.Popen(call, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
self.timeVLCLaunched = time.time() self.timeVLCLaunched = time.time()
@ -440,7 +416,10 @@ class VlcPlayer(BasePlayer):
self._sendingData = threading.Lock() self._sendingData = threading.Lock()
def _shouldListenForSTDOUT(self): def _shouldListenForSTDOUT(self):
return not isWindows() if isWindows():
return False # Due to VLC3 not using STDOUT/STDERR
else:
return True
def initiate_send(self): def initiate_send(self):
with self._sendingData: with self._sendingData:
@ -483,6 +462,7 @@ class VlcPlayer(BasePlayer):
break break
out.close() out.close()
def found_terminator(self): def found_terminator(self):
self.vlcHasResponded = True self.vlcHasResponded = True
self.__playerController.lineReceived(b"".join(self._ibuffer)) self.__playerController.lineReceived(b"".join(self._ibuffer))

View File

@ -1,16 +1,13 @@
# coding:utf8 # coding:utf8
import json
import time
from functools import wraps
from twisted.protocols.basic import LineReceiver from twisted.protocols.basic import LineReceiver
import json
import syncplay import syncplay
from syncplay.constants import PING_MOVING_AVERAGE_WEIGHT, CONTROLLED_ROOMS_MIN_VERSION, USER_READY_MIN_VERSION, SHARED_PLAYLIST_MIN_VERSION, CHAT_MIN_VERSION from functools import wraps
import time
from syncplay.messages import getMessage from syncplay.messages import getMessage
from syncplay.constants import PING_MOVING_AVERAGE_WEIGHT, CONTROLLED_ROOMS_MIN_VERSION, USER_READY_MIN_VERSION, SHARED_PLAYLIST_MIN_VERSION, CHAT_MIN_VERSION
from syncplay.utils import meetsMinVersion from syncplay.utils import meetsMinVersion
class JSONCommandProtocol(LineReceiver): class JSONCommandProtocol(LineReceiver):
def handleMessages(self, messages): def handleMessages(self, messages):
for message in messages.items(): for message in messages.items():
@ -105,11 +102,9 @@ class SyncClientProtocol(JSONCommandProtocol):
hello = {} hello = {}
hello["username"] = self._client.getUsername() hello["username"] = self._client.getUsername()
password = self._client.getPassword() password = self._client.getPassword()
if password: if password: hello["password"] = password
hello["password"] = password
room = self._client.getRoom() room = self._client.getRoom()
if room: if room: hello["room"] = {"name" :room}
hello["room"] = {"name": room}
hello["version"] = "1.2.255" # Used so newer clients work on 1.2.X server hello["version"] = "1.2.255" # Used so newer clients work on 1.2.X server
hello["realversion"] = syncplay.version hello["realversion"] = syncplay.version
hello["features"] = self._client.getFeatures() hello["features"] = self._client.getFeatures()
@ -165,8 +160,7 @@ class SyncClientProtocol(JSONCommandProtocol):
def sendRoomSetting(self, roomName, password=None): def sendRoomSetting(self, roomName, password=None):
setting = {} setting = {}
setting["name"] = roomName setting["name"] = roomName
if password: if password: setting["password"] = password
setting["password"] = password
self.sendSet({"room": setting}) self.sendSet({"room": setting})
def sendFileSetting(self, file_): def sendFileSetting(self, file_):
@ -237,8 +231,7 @@ class SyncClientProtocol(JSONCommandProtocol):
state["playstate"] = {} state["playstate"] = {}
state["playstate"]["position"] = position state["playstate"]["position"] = position
state["playstate"]["paused"] = paused state["playstate"]["paused"] = paused
if doSeek: if doSeek: state["playstate"]["doSeek"] = doSeek
state["playstate"]["doSeek"] = doSeek
state["ping"] = {} state["ping"] = {}
if latencyCalculation: if latencyCalculation:
state["ping"]["latencyCalculation"] = latencyCalculation state["ping"]["latencyCalculation"] = latencyCalculation
@ -262,7 +255,6 @@ class SyncClientProtocol(JSONCommandProtocol):
"password": password "password": password
} }
}) })
def handleChat(self,message): def handleChat(self,message):
username = message['username'] username = message['username']
userMessage = message['message'] userMessage = message['message']
@ -290,13 +282,13 @@ class SyncClientProtocol(JSONCommandProtocol):
} }
}) })
def handleError(self, error): def handleError(self, error):
self.dropWithError(error["message"]) self.dropWithError(error["message"])
def sendError(self, message): def sendError(self, message):
self.sendMessage({"Error": {"message": message}}) self.sendMessage({"Error": {"message": message}})
class SyncServerProtocol(JSONCommandProtocol): class SyncServerProtocol(JSONCommandProtocol):
def __init__(self, factory): def __init__(self, factory):
self._factory = factory self._factory = factory
@ -418,8 +410,7 @@ class SyncServerProtocol(JSONCommandProtocol):
hello["username"] = username hello["username"] = username
userIp = self.transport.getPeer().host userIp = self.transport.getPeer().host
room = self._watcher.getRoom() room = self._watcher.getRoom()
if room: if room: hello["room"] = {"name": room.getName()}
hello["room"] = {"name": room.getName()}
hello["version"] = clientVersion # Used so 1.2.X client works on newer server hello["version"] = clientVersion # Used so 1.2.X client works on newer server
hello["realversion"] = syncplay.version hello["realversion"] = syncplay.version
hello["motd"] = self._factory.getMotd(userIp, username, room, clientVersion) hello["motd"] = self._factory.getMotd(userIp, username, room, clientVersion)
@ -470,6 +461,7 @@ class SyncServerProtocol(JSONCommandProtocol):
} }
}) })
def sendSetReady(self, username, isReady, manuallyInitiated=True): def sendSetReady(self, username, isReady, manuallyInitiated=True):
self.sendSet({ self.sendSet({
"ready": { "ready": {
@ -564,6 +556,7 @@ class SyncServerProtocol(JSONCommandProtocol):
if self.serverIgnoringOnTheFly == 0 or forced: if self.serverIgnoringOnTheFly == 0 or forced:
self.sendMessage({"State": state}) self.sendMessage({"State": state})
def _extractStatePlaystateArguments(self, state): def _extractStatePlaystateArguments(self, state):
position = state["playstate"]["position"] if "position" in state["playstate"] else 0 position = state["playstate"]["position"] if "position" in state["playstate"] else 0
paused = state["playstate"]["paused"] if "paused" in state["playstate"] else None paused = state["playstate"]["paused"] if "paused" in state["playstate"] else None
@ -597,7 +590,6 @@ class SyncServerProtocol(JSONCommandProtocol):
def sendError(self, message): def sendError(self, message):
self.sendMessage({"Error": {"message": message}}) self.sendMessage({"Error": {"message": message}})
class PingService(object): class PingService(object):
def __init__(self): def __init__(self):

View File

@ -1,26 +1,20 @@
import argparse
import codecs
import hashlib import hashlib
import os
import random import random
import time
from string import Template
from twisted.internet import task, reactor from twisted.internet import task, reactor
from twisted.internet.protocol import Factory from twisted.internet.protocol import Factory
import syncplay import syncplay
from syncplay.protocols import SyncServerProtocol
import time
from syncplay import constants from syncplay import constants
from syncplay.messages import getMessage from syncplay.messages import getMessage
from syncplay.protocols import SyncServerProtocol import codecs
import os
from string import Template
import argparse
from syncplay.utils import RoomPasswordProvider, NotControlledRoom, RandomStringGenerator, meetsMinVersion, playlistIsValid, truncateText from syncplay.utils import RoomPasswordProvider, NotControlledRoom, RandomStringGenerator, meetsMinVersion, playlistIsValid, truncateText
class SyncFactory(Factory): class SyncFactory(Factory):
def __init__(self, password='', motdFilePath=None, isolateRooms=False, salt=None, def __init__(self, password='', motdFilePath=None, isolateRooms=False, salt=None, disableReady=False,disableChat=False, maxChatMessageLength=constants.MAX_CHAT_MESSAGE_LENGTH, maxUsernameLength=constants.MAX_USERNAME_LENGTH):
disableReady=False, disableChat=False, maxChatMessageLength=constants.MAX_CHAT_MESSAGE_LENGTH,
maxUsernameLength=constants.MAX_USERNAME_LENGTH):
self.isolateRooms = isolateRooms self.isolateRooms = isolateRooms
print(getMessage("welcome-server-notification").format(syncplay.version)) print(getMessage("welcome-server-notification").format(syncplay.version))
if password: if password:
@ -185,7 +179,6 @@ class SyncFactory(Factory):
else: else:
watcher.setPlaylistIndex(room.getName(), room.getPlaylistIndex()) watcher.setPlaylistIndex(room.getName(), room.getPlaylistIndex())
class RoomManager(object): class RoomManager(object):
def __init__(self): def __init__(self):
self._rooms = {} self._rooms = {}
@ -348,7 +341,6 @@ class Room(object):
def getPlaylistIndex(self): def getPlaylistIndex(self):
return self._playlistIndex return self._playlistIndex
class ControlledRoom(Room): class ControlledRoom(Room):
def __init__(self, name): def __init__(self, name):
Room.__init__(self, name) Room.__init__(self, name)
@ -397,7 +389,6 @@ class ControlledRoom(Room):
def getControllers(self): def getControllers(self):
return self._controllers return self._controllers
class Watcher(object): class Watcher(object):
def __init__(self, server, connector, name): def __init__(self, server, connector, name):
self._ready = None self._ready = None
@ -540,7 +531,6 @@ class Watcher(object):
return RoomPasswordProvider.isControlledRoom(self._room.getName()) \ return RoomPasswordProvider.isControlledRoom(self._room.getName()) \
and self._room.canControl(self) and self._room.canControl(self)
class ConfigurationGetter(object): class ConfigurationGetter(object):
def getConfiguration(self): def getConfiguration(self):
self._prepareArgParser() self._prepareArgParser()
@ -550,8 +540,7 @@ class ConfigurationGetter(object):
return args return args
def _prepareArgParser(self): def _prepareArgParser(self):
self._argparser = argparse.ArgumentParser( self._argparser = argparse.ArgumentParser(description=getMessage("server-argument-description"),
description=getMessage("server-argument-description"),
epilog=getMessage("server-argument-epilog")) epilog=getMessage("server-argument-epilog"))
self._argparser.add_argument('--port', metavar='port', type=str, nargs='?', help=getMessage("server-port-argument")) self._argparser.add_argument('--port', metavar='port', type=str, nargs='?', help=getMessage("server-port-argument"))
self._argparser.add_argument('--password', metavar='password', type=str, nargs='?', help=getMessage("server-password-argument")) self._argparser.add_argument('--password', metavar='password', type=str, nargs='?', help=getMessage("server-password-argument"))

View File

@ -1,23 +1,19 @@
from configparser import SafeConfigParser, DEFAULTSECT
import argparse import argparse
import ast
import codecs
import re
import os import os
import sys import sys
from configparser import SafeConfigParser, DEFAULTSECT import ast
from syncplay import constants, utils, version, milestone from syncplay import constants, utils, version, milestone
from syncplay.messages import getMessage, setLanguage, isValidLanguage from syncplay.messages import getMessage, setLanguage, isValidLanguage
from syncplay.players.playerFactory import PlayerFactory from syncplay.players.playerFactory import PlayerFactory
from syncplay.utils import isMacOS from syncplay.utils import isMacOS
import codecs
import re
class InvalidConfigValue(Exception): class InvalidConfigValue(Exception):
def __init__(self, message): def __init__(self, message):
Exception.__init__(self, message) Exception.__init__(self, message)
class ConfigurationGetter(object): class ConfigurationGetter(object):
def __init__(self): def __init__(self):
self._config = { self._config = {
@ -179,8 +175,7 @@ class ConfigurationGetter(object):
self._iniStructure = { self._iniStructure = {
"server_data": ["host", "port", "password"], "server_data": ["host", "port", "password"],
"client_settings": [ "client_settings": ["name", "room", "playerPath",
"name", "room", "playerPath",
"perPlayerArguments", "slowdownThreshold", "perPlayerArguments", "slowdownThreshold",
"rewindThreshold", "fastforwardThreshold", "rewindThreshold", "fastforwardThreshold",
"slowOnDesync", "rewindOnDesync", "slowOnDesync", "rewindOnDesync",
@ -192,8 +187,7 @@ class ConfigurationGetter(object):
"sharedPlaylistEnabled", "loopAtEndOfPlaylist", "sharedPlaylistEnabled", "loopAtEndOfPlaylist",
"loopSingleFiles", "loopSingleFiles",
"onlySwitchToTrustedDomains", "trustedDomains","publicServers"], "onlySwitchToTrustedDomains", "trustedDomains","publicServers"],
"gui": [ "gui": ["showOSD", "showOSDWarnings", "showSlowdownOSD",
"showOSD", "showOSDWarnings", "showSlowdownOSD",
"showDifferentRoomOSD", "showSameRoomOSD", "showDifferentRoomOSD", "showSameRoomOSD",
"showNonControllerOSD", "showDurationNotification", "showNonControllerOSD", "showDurationNotification",
"chatInputEnabled","chatInputFontUnderline", "chatInputEnabled","chatInputFontUnderline",
@ -208,8 +202,7 @@ class ConfigurationGetter(object):
"chatMoveOSD", "chatOSDMargin", "chatMoveOSD", "chatOSDMargin",
"notificationTimeout", "alertTimeout", "notificationTimeout", "alertTimeout",
"chatTimeout","chatOutputEnabled"], "chatTimeout","chatOutputEnabled"],
"general": [ "general": ["language", "checkForUpdatesAutomatically",
"language", "checkForUpdatesAutomatically",
"lastCheckedForUpdates"] "lastCheckedForUpdates"]
} }
@ -231,7 +224,7 @@ class ConfigurationGetter(object):
try: try:
if varToTest == "" or varToTest is None: if varToTest == "" or varToTest is None:
return False return False
if not str(varToTest).isdigit(): if str(varToTest).isdigit() == False:
return False return False
varToTest = int(varToTest) varToTest = int(varToTest)
if varToTest > 65535 or varToTest < 1: if varToTest > 65535 or varToTest < 1:
@ -239,7 +232,6 @@ class ConfigurationGetter(object):
return True return True
except: except:
return False return False
for key in self._boolean: for key in self._boolean:
if self._config[key] == "True": if self._config[key] == "True":
self._config[key] = True self._config[key] = True
@ -277,14 +269,13 @@ class ConfigurationGetter(object):
self._config["playerClass"] = player self._config["playerClass"] = player
else: else:
raise InvalidConfigValue(getMessage("player-path-config-error")) raise InvalidConfigValue(getMessage("player-path-config-error"))
playerPathErrors = player.getPlayerPathErrors( playerPathErrors = player.getPlayerPathErrors(self._config["playerPath"], self._config['file'] if self._config['file'] else None)
self._config["playerPath"], self._config['file'] if self._config['file'] else None)
if playerPathErrors: if playerPathErrors:
raise InvalidConfigValue(playerPathErrors) raise InvalidConfigValue(playerPathErrors)
elif key == "host": elif key == "host":
self._config["host"], self._config["port"] = self._splitPortAndHost(self._config["host"]) self._config["host"], self._config["port"] = self._splitPortAndHost(self._config["host"])
hostNotValid = (self._config["host"] == "" or self._config["host"] is None) hostNotValid = (self._config["host"] == "" or self._config["host"] is None)
portNotValid = (not _isPortValid(self._config["port"])) portNotValid = (_isPortValid(self._config["port"]) == False)
if hostNotValid: if hostNotValid:
raise InvalidConfigValue(getMessage("no-hostname-config-error")) raise InvalidConfigValue(getMessage("no-hostname-config-error"))
elif portNotValid: elif portNotValid:
@ -417,6 +408,7 @@ class ConfigurationGetter(object):
if changed: if changed:
parser.write(codecs.open(iniPath, "wb", "utf_8_sig")) parser.write(codecs.open(iniPath, "wb", "utf_8_sig"))
def _forceGuiPrompt(self): def _forceGuiPrompt(self):
from syncplay.ui.GuiConfiguration import GuiConfiguration from syncplay.ui.GuiConfiguration import GuiConfiguration
try: try:
@ -460,8 +452,7 @@ class ConfigurationGetter(object):
# #
if self._config['language']: if self._config['language']:
setLanguage(self._config['language']) setLanguage(self._config['language'])
self._argparser = argparse.ArgumentParser( self._argparser = argparse.ArgumentParser(description=getMessage("argument-description"),
description=getMessage("argument-description"),
epilog=getMessage("argument-epilog")) epilog=getMessage("argument-epilog"))
self._argparser.add_argument('--no-gui', action='store_true', help=getMessage("nogui-argument")) self._argparser.add_argument('--no-gui', action='store_true', help=getMessage("nogui-argument"))
self._argparser.add_argument('-a', '--host', metavar='hostname', type=str, help=getMessage("host-argument")) self._argparser.add_argument('-a', '--host', metavar='hostname', type=str, help=getMessage("host-argument"))
@ -523,7 +514,6 @@ class ConfigurationGetter(object):
self._saveConfig(path) self._saveConfig(path)
self._config = backup self._config = backup
class SafeConfigParserUnicode(SafeConfigParser): class SafeConfigParserUnicode(SafeConfigParser):
def write(self, fp): def write(self, fp):
"""Write an .ini-format representation of the configuration state.""" """Write an .ini-format representation of the configuration state."""

View File

@ -1,24 +1,19 @@
import os
import sys
import threading
from datetime import datetime
from syncplay import constants
from syncplay import utils
from syncplay.messages import getMessage, getLanguages, setLanguage, getInitialLanguage
from syncplay.players.playerFactory import PlayerFactory
from syncplay.utils import isBSD, isLinux, isMacOS, isWindows
from syncplay.utils import resourcespath, posixresourcespath
from syncplay.vendor.Qt import QtCore, QtWidgets, QtGui, __binding__, IsPySide, IsPySide2 from syncplay.vendor.Qt import QtCore, QtWidgets, QtGui, __binding__, IsPySide, IsPySide2
from syncplay.vendor.Qt.QtCore import Qt, QSettings, QCoreApplication, QSize, QPoint, QUrl, QLine, QEventLoop, Signal from syncplay.vendor.Qt.QtCore import Qt, QSettings, QCoreApplication, QSize, QPoint, QUrl, QLine, QEventLoop, Signal
from syncplay.vendor.Qt.QtWidgets import QApplication, QLineEdit, QLabel, QCheckBox, QButtonGroup, QRadioButton, QDoubleSpinBox, QPlainTextEdit from syncplay.vendor.Qt.QtWidgets import QApplication, QLineEdit, QLabel, QCheckBox, QButtonGroup, QRadioButton, QDoubleSpinBox, QPlainTextEdit
from syncplay.vendor.Qt.QtGui import QCursor, QIcon, QImage, QDesktopServices from syncplay.vendor.Qt.QtGui import QCursor, QIcon, QImage, QDesktopServices
if IsPySide2: if IsPySide2:
from PySide2.QtCore import QStandardPaths from PySide2.QtCore import QStandardPaths
from syncplay.players.playerFactory import PlayerFactory
from datetime import datetime
from syncplay import utils
import os
import sys
import threading
from syncplay.messages import getMessage, getLanguages, setLanguage, getInitialLanguage
from syncplay import constants
from syncplay.utils import isBSD, isLinux, isMacOS, isWindows
from syncplay.utils import resourcespath, posixresourcespath
class GuiConfiguration: class GuiConfiguration:
def __init__(self, config, error=None, defaultConfig=None): def __init__(self, config, error=None, defaultConfig=None):
self.defaultConfig = defaultConfig self.defaultConfig = defaultConfig
@ -87,10 +82,8 @@ class ConfigDialog(QtWidgets.QDialog):
def automaticUpdatePromptCheck(self): def automaticUpdatePromptCheck(self):
if self.automaticupdatesCheckbox.checkState() == Qt.PartiallyChecked: if self.automaticupdatesCheckbox.checkState() == Qt.PartiallyChecked:
reply = QtWidgets.QMessageBox.question( reply = QtWidgets.QMessageBox.question(self, "Syncplay",
self, "Syncplay", getMessage("promptforupdate-label"), QtWidgets.QMessageBox.StandardButton.Yes | QtWidgets.QMessageBox.StandardButton.No)
getMessage("promptforupdate-label"),
QtWidgets.QMessageBox.StandardButton.Yes | QtWidgets.QMessageBox.StandardButton.No)
if reply == QtWidgets.QMessageBox.Yes: if reply == QtWidgets.QMessageBox.Yes:
self.automaticupdatesCheckbox.setChecked(True) self.automaticupdatesCheckbox.setChecked(True)
else: else:
@ -98,7 +91,7 @@ class ConfigDialog(QtWidgets.QDialog):
def moreToggled(self): def moreToggled(self):
self.setSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) self.setSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
if self.moreToggling is False: if self.moreToggling == False:
self.moreToggling = True self.moreToggling = True
if self.showmoreCheckbox.isChecked(): if self.showmoreCheckbox.isChecked():
@ -161,7 +154,7 @@ class ConfigDialog(QtWidgets.QDialog):
settings.endGroup() settings.endGroup()
foundpath = "" foundpath = ""
if playerpath is not None and playerpath != "": if playerpath != None and playerpath != "":
if utils.isURL(playerpath): if utils.isURL(playerpath):
foundpath = playerpath foundpath = playerpath
self.executablepathCombobox.addItem(foundpath) self.executablepathCombobox.addItem(foundpath)
@ -169,7 +162,7 @@ class ConfigDialog(QtWidgets.QDialog):
else: else:
if not os.path.isfile(playerpath): if not os.path.isfile(playerpath):
expandedpath = PlayerFactory().getExpandedPlayerPathByPath(playerpath) expandedpath = PlayerFactory().getExpandedPlayerPathByPath(playerpath)
if expandedpath is not None and os.path.isfile(expandedpath): if expandedpath != None and os.path.isfile(expandedpath):
playerpath = expandedpath playerpath = expandedpath
if os.path.isfile(playerpath): if os.path.isfile(playerpath):
@ -259,8 +252,7 @@ class ConfigDialog(QtWidgets.QDialog):
elif isBSD(): elif isBSD():
defaultdirectory = "/usr/local/bin" defaultdirectory = "/usr/local/bin"
fileName, filtr = QtWidgets.QFileDialog.getOpenFileName( fileName, filtr = QtWidgets.QFileDialog.getOpenFileName(self,
self,
"Browse for media player executable", "Browse for media player executable",
defaultdirectory, defaultdirectory,
browserfilter, "", options) browserfilter, "", options)
@ -395,8 +387,7 @@ class ConfigDialog(QtWidgets.QDialog):
else: else:
defaultdirectory = "" defaultdirectory = ""
browserfilter = "All files (*)" browserfilter = "All files (*)"
fileName, filtr = QtWidgets.QFileDialog.getOpenFileName( fileName, filtr = QtWidgets.QFileDialog.getOpenFileName(self, "Browse for media files", defaultdirectory,
self, "Browse for media files", defaultdirectory,
browserfilter, "", options) browserfilter, "", options)
if fileName: if fileName:
self.mediapathTextbox.setText(os.path.normpath(fileName)) self.mediapathTextbox.setText(os.path.normpath(fileName))
@ -551,10 +542,10 @@ class ConfigDialog(QtWidgets.QDialog):
config = self.config config = self.config
playerpaths = self.playerpaths playerpaths = self.playerpaths
error = self.error error = self.error
if self.datacleared: if self.datacleared == True:
error = constants.ERROR_MESSAGE_MARKER + "{}".format(getMessage("gui-data-cleared-notification")) error = constants.ERROR_MESSAGE_MARKER + "{}".format(getMessage("gui-data-cleared-notification"))
self.error = error self.error = error
if config['host'] is None: if config['host'] == None:
host = "" host = ""
elif ":" in config['host']: elif ":" in config['host']:
host = config['host'] host = config['host']
@ -575,7 +566,7 @@ class ConfigDialog(QtWidgets.QDialog):
serverAddressPort = publicServer[1] serverAddressPort = publicServer[1]
self.hostCombobox.addItem(serverAddressPort) self.hostCombobox.addItem(serverAddressPort)
self.hostCombobox.setItemData(i, serverTitle, Qt.ToolTipRole) self.hostCombobox.setItemData(i, serverTitle, Qt.ToolTipRole)
if serverAddressPort not in self.publicServerAddresses: if not serverAddressPort in self.publicServerAddresses:
self.publicServerAddresses.append(serverAddressPort) self.publicServerAddresses.append(serverAddressPort)
i += 1 i += 1
self.hostCombobox.setEditable(True) self.hostCombobox.setEditable(True)
@ -1233,7 +1224,7 @@ class ConfigDialog(QtWidgets.QDialog):
def populateEmptyServerList(self): def populateEmptyServerList(self):
if self.publicServers is None: if self.publicServers is None:
if self.config["checkForUpdatesAutomatically"]: if self.config["checkForUpdatesAutomatically"] == True:
self.updateServerList() self.updateServerList()
else: else:
currentServer = self.hostCombobox.currentText() currentServer = self.hostCombobox.currentText()
@ -1273,7 +1264,7 @@ class ConfigDialog(QtWidgets.QDialog):
self._playerProbeThread.done.connect(self._updateExecutableIcon) self._playerProbeThread.done.connect(self._updateExecutableIcon)
self._playerProbeThread.start() self._playerProbeThread.start()
if self.config['clearGUIData']: if self.config['clearGUIData'] == True:
self.config['clearGUIData'] = False self.config['clearGUIData'] = False
self.clearGUIData() self.clearGUIData()
@ -1314,7 +1305,7 @@ class ConfigDialog(QtWidgets.QDialog):
self.addBottomLayout() self.addBottomLayout()
self.updatePasswordVisibilty() self.updatePasswordVisibilty()
if self.getMoreState() is False: if self.getMoreState() == False:
self.tabListFrame.hide() self.tabListFrame.hide()
self.resetButton.hide() self.resetButton.hide()
self.playerargsTextbox.hide() self.playerargsTextbox.hide()

View File

@ -1,5 +1,4 @@
import os import os
if "QT_PREFERRED_BINDING" not in os.environ: if "QT_PREFERRED_BINDING" not in os.environ:
os.environ["QT_PREFERRED_BINDING"] = os.pathsep.join( os.environ["QT_PREFERRED_BINDING"] = os.pathsep.join(
["PySide2", "PySide", "PyQt5", "PyQt4"] ["PySide2", "PySide", "PyQt5", "PyQt4"]
@ -11,9 +10,8 @@ except ImportError:
pass pass
from syncplay.ui.consoleUI import ConsoleUI from syncplay.ui.consoleUI import ConsoleUI
def getUi(graphical=True): def getUi(graphical=True):
if graphical: if graphical: #TODO: Add graphical ui
ui = GraphicalUI() ui = GraphicalUI()
else: else:
ui = ConsoleUI() ui = ConsoleUI()

View File

@ -1,16 +1,14 @@
import re
import sys
import threading import threading
import time import time
import syncplay import syncplay
from syncplay import constants import re
from syncplay import utils from syncplay import utils
from syncplay import constants
from syncplay.messages import getMessage from syncplay.messages import getMessage
import sys
from syncplay.utils import formatTime from syncplay.utils import formatTime
class ConsoleUI(threading.Thread): class ConsoleUI(threading.Thread):
def __init__(self): def __init__(self):
self.promptMode = threading.Event() self.promptMode = threading.Event()
@ -159,7 +157,7 @@ class ConsoleUI(threading.Thread):
self._syncplayClient.setPaused(not self._syncplayClient.getPlayerPaused()) self._syncplayClient.setPaused(not self._syncplayClient.getPlayerPaused())
elif command.group('command') in constants.COMMANDS_ROOM: elif command.group('command') in constants.COMMANDS_ROOM:
room = command.group('parameter') room = command.group('parameter')
if room is None: if room == None:
if self._syncplayClient.userlist.currentUser.file: if self._syncplayClient.userlist.currentUser.file:
room = self._syncplayClient.userlist.currentUser.file["name"] room = self._syncplayClient.userlist.currentUser.file["name"]
else: else:
@ -169,7 +167,7 @@ class ConsoleUI(threading.Thread):
self._syncplayClient.sendRoom() self._syncplayClient.sendRoom()
elif command.group('command') in constants.COMMANDS_CREATE: elif command.group('command') in constants.COMMANDS_CREATE:
roombasename = command.group('parameter') roombasename = command.group('parameter')
if roombasename is None: if roombasename == None:
roombasename = self._syncplayClient.getRoom() roombasename = self._syncplayClient.getRoom()
roombasename = utils.stripRoomName(roombasename) roombasename = utils.stripRoomName(roombasename)
self._syncplayClient.createControlledRoom(roombasename) self._syncplayClient.createControlledRoom(roombasename)

View File

@ -1,34 +1,28 @@
import os
import re
import sys
import time
import urllib.error
import urllib.parse
import urllib.request
from datetime import datetime
from functools import wraps
from platform import python_version
from twisted.internet import task
from syncplay import utils, constants, version, revision, release_number
from syncplay.messages import getMessage
from syncplay.ui.consoleUI import ConsoleUI
from syncplay.utils import resourcespath
from syncplay.utils import isLinux, isWindows, isMacOS
from syncplay.utils import formatTime, sameFilename, sameFilesize, sameFileduration, RoomPasswordProvider, formatSize, isURL
from syncplay.vendor import Qt from syncplay.vendor import Qt
from syncplay.vendor.Qt import QtWidgets, QtGui, __binding__, __binding_version__, __qt_version__, IsPySide, IsPySide2 from syncplay.vendor.Qt import QtWidgets, QtGui, __binding__, __binding_version__, __qt_version__, IsPySide, IsPySide2
from syncplay.vendor.Qt.QtCore import Qt, QSettings, QSize, QPoint, QUrl, QLine, QDateTime from syncplay.vendor.Qt.QtCore import Qt, QSettings, QSize, QPoint, QUrl, QLine, QDateTime
from platform import python_version
if IsPySide2: if IsPySide2:
from PySide2.QtCore import QStandardPaths from PySide2.QtCore import QStandardPaths
from syncplay import utils, constants, version, revision, release_number
from syncplay.messages import getMessage
from syncplay.utils import resourcespath
import sys
import time
import urllib.request, urllib.parse, urllib.error
from datetime import datetime
from syncplay.utils import isLinux, isWindows, isMacOS
import re
import os
from syncplay.utils import formatTime, sameFilename, sameFilesize, sameFileduration, RoomPasswordProvider, formatSize, isURL
from functools import wraps
from twisted.internet import task
from syncplay.ui.consoleUI import ConsoleUI
if isMacOS() and IsPySide: if isMacOS() and IsPySide:
from Foundation import NSURL from Foundation import NSURL
from Cocoa import NSString, NSUTF8StringEncoding from Cocoa import NSString, NSUTF8StringEncoding
lastCheckedForUpdates = None lastCheckedForUpdates = None
class ConsoleInGUI(ConsoleUI): class ConsoleInGUI(ConsoleUI):
def showMessage(self, message, noTimestamp=False): def showMessage(self, message, noTimestamp=False):
self._syncplayClient.ui.showMessage(message, True) self._syncplayClient.ui.showMessage(message, True)
@ -45,7 +39,6 @@ class ConsoleInGUI(ConsoleUI):
def getUserlist(self): def getUserlist(self):
self._syncplayClient.showUserList(self) self._syncplayClient.showUserList(self)
class UserlistItemDelegate(QtWidgets.QStyledItemDelegate): class UserlistItemDelegate(QtWidgets.QStyledItemDelegate):
def __init__(self): def __init__(self):
QtWidgets.QStyledItemDelegate.__init__(self) QtWidgets.QStyledItemDelegate.__init__(self)
@ -109,7 +102,6 @@ class UserlistItemDelegate(QtWidgets.QStyledItemDelegate):
optionQStyleOptionViewItem.rect.setX(optionQStyleOptionViewItem.rect.x()+16) optionQStyleOptionViewItem.rect.setX(optionQStyleOptionViewItem.rect.x()+16)
QtWidgets.QStyledItemDelegate.paint(self, itemQPainter, optionQStyleOptionViewItem, indexQModelIndex) QtWidgets.QStyledItemDelegate.paint(self, itemQPainter, optionQStyleOptionViewItem, indexQModelIndex)
class AboutDialog(QtWidgets.QDialog): class AboutDialog(QtWidgets.QDialog):
def __init__(self, parent=None): def __init__(self, parent=None):
super(AboutDialog, self).__init__(parent) super(AboutDialog, self).__init__(parent)
@ -125,13 +117,9 @@ class AboutDialog(QtWidgets.QDialog):
linkLabel = QtWidgets.QLabel("<center><a href=\"https://syncplay.pl\">syncplay.pl</a></center>") linkLabel = QtWidgets.QLabel("<center><a href=\"https://syncplay.pl\">syncplay.pl</a></center>")
linkLabel.setOpenExternalLinks(True) linkLabel.setOpenExternalLinks(True)
versionExtString = version + revision versionExtString = version + revision
versionLabel = QtWidgets.QLabel( versionLabel = QtWidgets.QLabel("<p><center>" + getMessage("about-dialog-release").format(versionExtString, release_number) + "<br />Python " + python_version() + " - " + __binding__ + " " + __binding_version__ + " - Qt " + __qt_version__ + "</center></p>")
"<p><center>" + getMessage("about-dialog-release").format(versionExtString, release_number) + #versionLabel = QtWidgets.QLabel("<p><center>Version 1.5.4 release 62<br />Python 3.4.5 - PySide 1.2.4 - Qt 4.8.7</center></p>")
"<br />Python " + python_version() + " - " + __binding__ + " " + __binding_version__ + licenseLabel = QtWidgets.QLabel("<center><p>Copyright &copy; 2012&ndash;2018 Syncplay</p><p>" + getMessage("about-dialog-license-text") + "</p></center>")
" - Qt " + __qt_version__ + "</center></p>")
licenseLabel = QtWidgets.QLabel(
"<center><p>Copyright &copy; 2012&ndash;2018 Syncplay</p><p>" +
getMessage("about-dialog-license-text") + "</p></center>")
aboutIconPixmap = QtGui.QPixmap(resourcespath + "syncplay.png") aboutIconPixmap = QtGui.QPixmap(resourcespath + "syncplay.png")
aboutIconLabel = QtWidgets.QLabel() aboutIconLabel = QtWidgets.QLabel()
aboutIconLabel.setPixmap(aboutIconPixmap.scaled(65, 65, Qt.KeepAspectRatio)) aboutIconLabel.setPixmap(aboutIconPixmap.scaled(65, 65, Qt.KeepAspectRatio))
@ -166,7 +154,6 @@ class AboutDialog(QtWidgets.QDialog):
else: else:
QtGui.QDesktopServices.openUrl(QUrl("file://" + resourcespath + "third-party-notices.rtf")) QtGui.QDesktopServices.openUrl(QUrl("file://" + resourcespath + "third-party-notices.rtf"))
class MainWindow(QtWidgets.QMainWindow): class MainWindow(QtWidgets.QMainWindow):
insertPosition = None insertPosition = None
playlistState = [] playlistState = []
@ -360,6 +347,8 @@ class MainWindow(QtWidgets.QMainWindow):
else: else:
super(MainWindow.PlaylistWidget, self).dropEvent(event) super(MainWindow.PlaylistWidget, self).dropEvent(event)
class topSplitter(QtWidgets.QSplitter): class topSplitter(QtWidgets.QSplitter):
def createHandle(self): def createHandle(self):
return self.topSplitterHandle(self.orientation(), self) return self.topSplitterHandle(self.orientation(), self)
@ -481,16 +470,9 @@ class MainWindow(QtWidgets.QMainWindow):
def showUserList(self, currentUser, rooms): def showUserList(self, currentUser, rooms):
self._usertreebuffer = QtGui.QStandardItemModel() self._usertreebuffer = QtGui.QStandardItemModel()
self._usertreebuffer.setHorizontalHeaderLabels( self._usertreebuffer.setHorizontalHeaderLabels(
( (getMessage("roomuser-heading-label"), getMessage("size-heading-label"), getMessage("duration-heading-label"), getMessage("filename-heading-label") ))
getMessage("roomuser-heading-label"), getMessage("size-heading-label"),
getMessage("duration-heading-label"), getMessage("filename-heading-label")
))
usertreeRoot = self._usertreebuffer.invisibleRootItem() usertreeRoot = self._usertreebuffer.invisibleRootItem()
if ( if self._syncplayClient.userlist.currentUser.file and self._syncplayClient.userlist.currentUser.file and os.path.isfile(self._syncplayClient.userlist.currentUser.file["path"]):
self._syncplayClient.userlist.currentUser.file and
self._syncplayClient.userlist.currentUser.file and
os.path.isfile(self._syncplayClient.userlist.currentUser.file["path"])
):
self._syncplayClient.fileSwitch.setCurrentDirectory(os.path.dirname(self._syncplayClient.userlist.currentUser.file["path"])) self._syncplayClient.fileSwitch.setCurrentDirectory(os.path.dirname(self._syncplayClient.userlist.currentUser.file["path"]))
for room in rooms: for room in rooms:
@ -631,6 +613,7 @@ class MainWindow(QtWidgets.QMainWindow):
menu.addAction(QtGui.QPixmap(resourcespath + "shield_edit.png"), getMessage("settrusteddomains-menu-label"), lambda: self.openSetTrustedDomainsDialog()) menu.addAction(QtGui.QPixmap(resourcespath + "shield_edit.png"), getMessage("settrusteddomains-menu-label"), lambda: self.openSetTrustedDomainsDialog())
menu.exec_(self.playlist.viewport().mapToGlobal(position)) menu.exec_(self.playlist.viewport().mapToGlobal(position))
def openRoomMenu(self, position): def openRoomMenu(self, position):
# TODO: Deselect items after right click # TODO: Deselect items after right click
indexes = self.listTreeView.selectedIndexes() indexes = self.listTreeView.selectedIndexes()
@ -711,7 +694,7 @@ class MainWindow(QtWidgets.QMainWindow):
def updateReadyState(self, newState): def updateReadyState(self, newState):
oldState = self.readyPushButton.isChecked() oldState = self.readyPushButton.isChecked()
if newState != oldState and newState is not None: if newState != oldState and newState != None:
self.readyPushButton.blockSignals(True) self.readyPushButton.blockSignals(True)
self.readyPushButton.setChecked(newState) self.readyPushButton.setChecked(newState)
self.readyPushButton.blockSignals(False) self.readyPushButton.blockSignals(False)
@ -785,7 +768,7 @@ class MainWindow(QtWidgets.QMainWindow):
@needsClient @needsClient
def joinRoom(self, room=None): def joinRoom(self, room=None):
if room is None: if room == None:
room = self.roomInput.text() room = self.roomInput.text()
if room == "": if room == "":
if self._syncplayClient.userlist.currentUser.file: if self._syncplayClient.userlist.currentUser.file:
@ -798,13 +781,14 @@ class MainWindow(QtWidgets.QMainWindow):
self._syncplayClient.sendRoom() self._syncplayClient.sendRoom()
def seekPositionDialog(self): def seekPositionDialog(self):
seekTime, ok = QtWidgets.QInputDialog.getText( seekTime, ok = QtWidgets.QInputDialog.getText(self, getMessage("seektime-menu-label"),
self, getMessage("seektime-menu-label"),
getMessage("seektime-msgbox-label"), QtWidgets.QLineEdit.Normal, getMessage("seektime-msgbox-label"), QtWidgets.QLineEdit.Normal,
"0:00") "0:00")
if ok and seekTime != '': if ok and seekTime != '':
self.seekPosition(seekTime) self.seekPosition(seekTime)
def seekFromButton(self): def seekFromButton(self):
self.seekPosition(self.seekInput.text()) self.seekPosition(self.seekInput.text())
@ -887,7 +871,7 @@ class MainWindow(QtWidgets.QMainWindow):
@needsClient @needsClient
def browseMediapath(self): def browseMediapath(self):
if self._syncplayClient._player.customOpenDialog: if self._syncplayClient._player.customOpenDialog == True:
self._syncplayClient._player.openCustomOpenDialog() self._syncplayClient._player.openCustomOpenDialog()
return return
@ -903,8 +887,7 @@ class MainWindow(QtWidgets.QMainWindow):
else: else:
defaultdirectory = self.getInitialMediaDirectory() defaultdirectory = self.getInitialMediaDirectory()
browserfilter = "All files (*)" browserfilter = "All files (*)"
fileName, filtr = QtWidgets.QFileDialog.getOpenFileName( fileName, filtr = QtWidgets.QFileDialog.getOpenFileName(self, getMessage("browseformedia-label"), defaultdirectory,
self, getMessage("browseformedia-label"), defaultdirectory,
browserfilter, "", options) browserfilter, "", options)
if fileName: if fileName:
if isWindows(): if isWindows():
@ -916,7 +899,7 @@ class MainWindow(QtWidgets.QMainWindow):
@needsClient @needsClient
def OpenAddFilesToPlaylistDialog(self): def OpenAddFilesToPlaylistDialog(self):
if self._syncplayClient._player.customOpenDialog: if self._syncplayClient._player.customOpenDialog == True:
self._syncplayClient._player.openCustomOpenDialog() self._syncplayClient._player.openCustomOpenDialog()
return return
@ -932,8 +915,7 @@ class MainWindow(QtWidgets.QMainWindow):
else: else:
defaultdirectory = self.getInitialMediaDirectory() defaultdirectory = self.getInitialMediaDirectory()
browserfilter = "All files (*)" browserfilter = "All files (*)"
fileNames, filtr = QtWidgets.QFileDialog.getOpenFileNames( fileNames, filtr = QtWidgets.QFileDialog.getOpenFileNames(self, getMessage("browseformedia-label"), defaultdirectory,
self, getMessage("browseformedia-label"), defaultdirectory,
browserfilter, "", options) browserfilter, "", options)
self.updatingPlaylist = True self.updatingPlaylist = True
if fileNames: if fileNames:
@ -1064,7 +1046,6 @@ class MainWindow(QtWidgets.QMainWindow):
if result == QtWidgets.QDialog.Accepted: if result == QtWidgets.QDialog.Accepted:
newTrustedDomains = utils.convertMultilineStringToList(TrustedDomainsTextbox.toPlainText()) newTrustedDomains = utils.convertMultilineStringToList(TrustedDomainsTextbox.toPlainText())
self._syncplayClient.setTrustedDomains(newTrustedDomains) self._syncplayClient.setTrustedDomains(newTrustedDomains)
@needsClient @needsClient
def addTrustedDomain(self, newDomain): def addTrustedDomain(self, newDomain):
trustedDomains = self.config["trustedDomains"][:] trustedDomains = self.config["trustedDomains"][:]
@ -1078,8 +1059,7 @@ class MainWindow(QtWidgets.QMainWindow):
options = QtWidgets.QFileDialog.Options(QtWidgets.QFileDialog.ShowDirsOnly | QtWidgets.QFileDialog.DontUseNativeDialog) options = QtWidgets.QFileDialog.Options(QtWidgets.QFileDialog.ShowDirsOnly | QtWidgets.QFileDialog.DontUseNativeDialog)
else: else:
options = QtWidgets.QFileDialog.Options(QtWidgets.QFileDialog.ShowDirsOnly) options = QtWidgets.QFileDialog.Options(QtWidgets.QFileDialog.ShowDirsOnly)
folderName = str(QtWidgets.QFileDialog.getExistingDirectory( folderName = str(QtWidgets.QFileDialog.getExistingDirectory(self,None,self.getInitialMediaDirectory(includeUserSpecifiedDirectories=False),options))
self, None, self.getInitialMediaDirectory(includeUserSpecifiedDirectories=False), options))
if folderName: if folderName:
existingMediaDirs = MediaDirectoriesTextbox.toPlainText() existingMediaDirs = MediaDirectoriesTextbox.toPlainText()
@ -1093,16 +1073,15 @@ class MainWindow(QtWidgets.QMainWindow):
@needsClient @needsClient
def promptForStreamURL(self): def promptForStreamURL(self):
streamURL, ok = QtWidgets.QInputDialog.getText( streamURL, ok = QtWidgets.QInputDialog.getText(self, getMessage("promptforstreamurl-msgbox-label"),
self, getMessage("promptforstreamurl-msgbox-label"), getMessage("promptforstreamurlinfo-msgbox-label"), QtWidgets.QLineEdit.Normal,
getMessage("promptforstreamurlinfo-msgbox-label"), QtWidgets.QLineEdit.Normal, "") "")
if ok and streamURL != '': if ok and streamURL != '':
self._syncplayClient._player.openFile(streamURL) self._syncplayClient._player.openFile(streamURL)
@needsClient @needsClient
def createControlledRoom(self): def createControlledRoom(self):
controlroom, ok = QtWidgets.QInputDialog.getText( controlroom, ok = QtWidgets.QInputDialog.getText(self, getMessage("createcontrolledroom-msgbox-label"),
self, getMessage("createcontrolledroom-msgbox-label"),
getMessage("controlledroominfo-msgbox-label"), QtWidgets.QLineEdit.Normal, getMessage("controlledroominfo-msgbox-label"), QtWidgets.QLineEdit.Normal,
utils.stripRoomName(self._syncplayClient.getRoom())) utils.stripRoomName(self._syncplayClient.getRoom()))
if ok and controlroom != '': if ok and controlroom != '':
@ -1127,9 +1106,9 @@ class MainWindow(QtWidgets.QMainWindow):
@needsClient @needsClient
def setOffset(self): def setOffset(self):
newoffset, ok = QtWidgets.QInputDialog.getText( newoffset, ok = QtWidgets.QInputDialog.getText(self, getMessage("setoffset-msgbox-label"),
self, getMessage("setoffset-msgbox-label"), getMessage("offsetinfo-msgbox-label"), QtWidgets.QLineEdit.Normal,
getMessage("offsetinfo-msgbox-label"), QtWidgets.QLineEdit.Normal, "") "")
if ok and newoffset != '': if ok and newoffset != '':
o = re.match(constants.UI_OFFSET_REGEX, "o " + newoffset) o = re.match(constants.UI_OFFSET_REGEX, "o " + newoffset)
if o: if o:
@ -1208,8 +1187,7 @@ class MainWindow(QtWidgets.QMainWindow):
window.chatInput = QtWidgets.QLineEdit() window.chatInput = QtWidgets.QLineEdit()
window.chatInput.setMaxLength(constants.MAX_CHAT_MESSAGE_LENGTH) window.chatInput.setMaxLength(constants.MAX_CHAT_MESSAGE_LENGTH)
window.chatInput.returnPressed.connect(self.sendChatMessage) window.chatInput.returnPressed.connect(self.sendChatMessage)
window.chatButton = QtWidgets.QPushButton( window.chatButton = QtWidgets.QPushButton(QtGui.QPixmap(resourcespath + 'email_go.png'),
QtGui.QPixmap(resourcespath + 'email_go.png'),
getMessage("sendmessage-label")) getMessage("sendmessage-label"))
window.chatButton.pressed.connect(self.sendChatMessage) window.chatButton.pressed.connect(self.sendChatMessage)
window.chatLayout = QtWidgets.QHBoxLayout() window.chatLayout = QtWidgets.QHBoxLayout()
@ -1264,8 +1242,7 @@ class MainWindow(QtWidgets.QMainWindow):
window.roomInput = QtWidgets.QLineEdit() window.roomInput = QtWidgets.QLineEdit()
window.roomInput.setMaxLength(constants.MAX_ROOM_NAME_LENGTH) window.roomInput.setMaxLength(constants.MAX_ROOM_NAME_LENGTH)
window.roomInput.returnPressed.connect(self.joinRoom) window.roomInput.returnPressed.connect(self.joinRoom)
window.roomButton = QtWidgets.QPushButton( window.roomButton = QtWidgets.QPushButton(QtGui.QPixmap(resourcespath + 'door_in.png'),
QtGui.QPixmap(resourcespath + 'door_in.png'),
getMessage("joinroom-label")) getMessage("joinroom-label"))
window.roomButton.pressed.connect(self.joinRoom) window.roomButton.pressed.connect(self.joinRoom)
window.roomLayout = QtWidgets.QHBoxLayout() window.roomLayout = QtWidgets.QHBoxLayout()
@ -1428,6 +1405,7 @@ class MainWindow(QtWidgets.QMainWindow):
getMessage("setmediadirectories-menu-label")) getMessage("setmediadirectories-menu-label"))
window.openAction.triggered.connect(self.openSetMediaDirectoriesDialog) window.openAction.triggered.connect(self.openSetMediaDirectoriesDialog)
window.exitAction = window.fileMenu.addAction(QtGui.QPixmap(resourcespath + 'cross.png'), window.exitAction = window.fileMenu.addAction(QtGui.QPixmap(resourcespath + 'cross.png'),
getMessage("exit-menu-label")) getMessage("exit-menu-label"))
window.exitAction.triggered.connect(self.exitSyncplay) window.exitAction.triggered.connect(self.exitSyncplay)
@ -1436,21 +1414,13 @@ class MainWindow(QtWidgets.QMainWindow):
# Playback menu # Playback menu
window.playbackMenu = QtWidgets.QMenu(getMessage("playback-menu-label"), self) window.playbackMenu = QtWidgets.QMenu(getMessage("playback-menu-label"), self)
window.playAction = window.playbackMenu.addAction( window.playAction = window.playbackMenu.addAction(QtGui.QPixmap(resourcespath + 'control_play_blue.png'), getMessage("play-menu-label"))
QtGui.QPixmap(resourcespath + 'control_play_blue.png'),
getMessage("play-menu-label"))
window.playAction.triggered.connect(self.play) window.playAction.triggered.connect(self.play)
window.pauseAction = window.playbackMenu.addAction( window.pauseAction = window.playbackMenu.addAction(QtGui.QPixmap(resourcespath + 'control_pause_blue.png'), getMessage("pause-menu-label"))
QtGui.QPixmap(resourcespath + 'control_pause_blue.png'),
getMessage("pause-menu-label"))
window.pauseAction.triggered.connect(self.pause) window.pauseAction.triggered.connect(self.pause)
window.seekAction = window.playbackMenu.addAction( window.seekAction = window.playbackMenu.addAction(QtGui.QPixmap(resourcespath + 'clock_go.png'), getMessage("seektime-menu-label"))
QtGui.QPixmap(resourcespath + 'clock_go.png'),
getMessage("seektime-menu-label"))
window.seekAction.triggered.connect(self.seekPositionDialog) window.seekAction.triggered.connect(self.seekPositionDialog)
window.unseekAction = window.playbackMenu.addAction( window.unseekAction = window.playbackMenu.addAction(QtGui.QPixmap(resourcespath + 'arrow_undo.png'), getMessage("undoseek-menu-label"))
QtGui.QPixmap(resourcespath + 'arrow_undo.png'),
getMessage("undoseek-menu-label"))
window.unseekAction.triggered.connect(self.undoSeek) window.unseekAction.triggered.connect(self.undoSeek)
window.menuBar.addMenu(window.playbackMenu) window.menuBar.addMenu(window.playbackMenu)
@ -1458,12 +1428,10 @@ class MainWindow(QtWidgets.QMainWindow):
# Advanced menu # Advanced menu
window.advancedMenu = QtWidgets.QMenu(getMessage("advanced-menu-label"), self) window.advancedMenu = QtWidgets.QMenu(getMessage("advanced-menu-label"), self)
window.setoffsetAction = window.advancedMenu.addAction( window.setoffsetAction = window.advancedMenu.addAction(QtGui.QPixmap(resourcespath + 'timeline_marker.png'),
QtGui.QPixmap(resourcespath + 'timeline_marker.png'),
getMessage("setoffset-menu-label")) getMessage("setoffset-menu-label"))
window.setoffsetAction.triggered.connect(self.setOffset) window.setoffsetAction.triggered.connect(self.setOffset)
window.setTrustedDomainsAction = window.advancedMenu.addAction( window.setTrustedDomainsAction = window.advancedMenu.addAction(QtGui.QPixmap(resourcespath + 'shield_edit.png'),
QtGui.QPixmap(resourcespath + 'shield_edit.png'),
getMessage("settrusteddomains-menu-label")) getMessage("settrusteddomains-menu-label"))
window.setTrustedDomainsAction.triggered.connect(self.openSetTrustedDomainsDialog) window.setTrustedDomainsAction.triggered.connect(self.openSetTrustedDomainsDialog)
window.createcontrolledroomAction = window.advancedMenu.addAction( window.createcontrolledroomAction = window.advancedMenu.addAction(
@ -1488,23 +1456,21 @@ class MainWindow(QtWidgets.QMainWindow):
window.autoplayAction.triggered.connect(self.updateAutoplayVisibility) window.autoplayAction.triggered.connect(self.updateAutoplayVisibility)
window.menuBar.addMenu(window.windowMenu) window.menuBar.addMenu(window.windowMenu)
# Help menu # Help menu
window.helpMenu = QtWidgets.QMenu(getMessage("help-menu-label"), self) window.helpMenu = QtWidgets.QMenu(getMessage("help-menu-label"), self)
window.userguideAction = window.helpMenu.addAction( window.userguideAction = window.helpMenu.addAction(QtGui.QPixmap(resourcespath + 'help.png'),
QtGui.QPixmap(resourcespath + 'help.png'),
getMessage("userguide-menu-label")) getMessage("userguide-menu-label"))
window.userguideAction.triggered.connect(self.openUserGuide) window.userguideAction.triggered.connect(self.openUserGuide)
window.updateAction = window.helpMenu.addAction( window.updateAction = window.helpMenu.addAction(QtGui.QPixmap(resourcespath + 'application_get.png'),
QtGui.QPixmap(resourcespath + 'application_get.png'),
getMessage("update-menu-label")) getMessage("update-menu-label"))
window.updateAction.triggered.connect(self.userCheckForUpdates) window.updateAction.triggered.connect(self.userCheckForUpdates)
if not isMacOS(): if not isMacOS():
window.helpMenu.addSeparator() window.helpMenu.addSeparator()
window.about = window.helpMenu.addAction( window.about = window.helpMenu.addAction(QtGui.QPixmap(resourcespath + 'syncplay.png'),
QtGui.QPixmap(resourcespath + 'syncplay.png'),
getMessage("about-menu-label")) getMessage("about-menu-label"))
else: else:
window.about = window.helpMenu.addAction("&About") window.about = window.helpMenu.addAction("&About")
@ -1562,7 +1528,7 @@ class MainWindow(QtWidgets.QMainWindow):
def updateAutoPlayState(self, newState): def updateAutoPlayState(self, newState):
oldState = self.autoplayPushButton.isChecked() oldState = self.autoplayPushButton.isChecked()
if newState != oldState and newState is not None: if newState != oldState and newState != None:
self.autoplayPushButton.blockSignals(True) self.autoplayPushButton.blockSignals(True)
self.autoplayPushButton.setChecked(newState) self.autoplayPushButton.setChecked(newState)
self.autoplayPushButton.blockSignals(False) self.autoplayPushButton.blockSignals(False)
@ -1625,11 +1591,10 @@ class MainWindow(QtWidgets.QMainWindow):
else: else:
import syncplay import syncplay
updateMessage = getMessage("update-check-failed-notification").format(syncplay.version) updateMessage = getMessage("update-check-failed-notification").format(syncplay.version)
if userInitiated: if userInitiated == True:
updateURL = constants.SYNCPLAY_DOWNLOAD_URL updateURL = constants.SYNCPLAY_DOWNLOAD_URL
if updateURL is not None: if updateURL is not None:
reply = QtWidgets.QMessageBox.question( reply = QtWidgets.QMessageBox.question(self, "Syncplay",
self, "Syncplay",
updateMessage, QtWidgets.QMessageBox.StandardButton.Yes | QtWidgets.QMessageBox.StandardButton.No) updateMessage, QtWidgets.QMessageBox.StandardButton.Yes | QtWidgets.QMessageBox.StandardButton.No)
if reply == QtWidgets.QMessageBox.Yes: if reply == QtWidgets.QMessageBox.Yes:
self.QtGui.QDesktopServices.openUrl(QUrl(updateURL)) self.QtGui.QDesktopServices.openUrl(QUrl(updateURL))
@ -1659,7 +1624,7 @@ class MainWindow(QtWidgets.QMainWindow):
dropfilepath = os.path.abspath(NSURL.URLWithString_(pathString).filePathURL().path()) dropfilepath = os.path.abspath(NSURL.URLWithString_(pathString).filePathURL().path())
else: else:
dropfilepath = os.path.abspath(str(url.toLocalFile())) dropfilepath = os.path.abspath(str(url.toLocalFile()))
if not rewindFile: if rewindFile == False:
self._syncplayClient._player.openFile(dropfilepath) self._syncplayClient._player.openFile(dropfilepath)
else: else:
self._syncplayClient.setPosition(0) self._syncplayClient.setPosition(0)

View File

@ -1,44 +1,35 @@
import ast
import datetime
import hashlib
import itertools
import random
import os
import platform
import re
import string
import subprocess
import sys
import time import time
import traceback import re
import unicodedata import datetime
import urllib.error
import urllib.parse
import urllib.request
from syncplay import constants from syncplay import constants
from syncplay.messages import getMessage from syncplay.messages import getMessage
import sys
import os
import itertools
import hashlib
import random
import string
import urllib.request, urllib.parse, urllib.error
import ast
import unicodedata
import platform
import subprocess
import traceback
folderSearchEnabled = True folderSearchEnabled = True
def isWindows(): def isWindows():
return sys.platform.startswith(constants.OS_WINDOWS) return sys.platform.startswith(constants.OS_WINDOWS)
def isLinux(): def isLinux():
return sys.platform.startswith(constants.OS_LINUX) return sys.platform.startswith(constants.OS_LINUX)
def isMacOS(): def isMacOS():
return sys.platform.startswith(constants.OS_MACOS) return sys.platform.startswith(constants.OS_MACOS)
def isBSD(): def isBSD():
return constants.OS_BSD in sys.platform or sys.platform.startswith(constants.OS_DRAGONFLY) 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): def retry(ExceptionToCheck, tries=4, delay=3, backoff=2, logger=None):
"""Retry calling the decorated function using an exponential backoff. """Retry calling the decorated function using an exponential backoff.
@ -80,7 +71,6 @@ def retry(ExceptionToCheck, tries=4, delay=3, backoff=2, logger=None):
return f_retry # true decorator return f_retry # true decorator
return deco_retry return deco_retry
def parseTime(timeStr): def parseTime(timeStr):
regex = re.compile(constants.PARSE_TIME_REGEX) regex = re.compile(constants.PARSE_TIME_REGEX)
parts = regex.match(timeStr) parts = regex.match(timeStr)
@ -96,7 +86,6 @@ def parseTime(timeStr):
time_params[name] = int(param) time_params[name] = int(param)
return datetime.timedelta(**time_params).total_seconds() return datetime.timedelta(**time_params).total_seconds()
def formatTime(timeInSeconds, weeksAsTitles=True): def formatTime(timeInSeconds, weeksAsTitles=True):
if timeInSeconds < 0: if timeInSeconds < 0:
timeInSeconds = -timeInSeconds timeInSeconds = -timeInSeconds
@ -126,8 +115,7 @@ def formatTime(timeInSeconds, weeksAsTitles=True):
formattedTime = "{0:} (Title {1:.0f})".format(formattedTime, title) formattedTime = "{0:} (Title {1:.0f})".format(formattedTime, title)
return formattedTime return formattedTime
def formatSize (bytes, precise=False):
def formatSize(num_of_bytes, precise=False):
if bytes == 0: # E.g. when file size privacy is enabled if bytes == 0: # E.g. when file size privacy is enabled
return "???" return "???"
try: try:
@ -140,11 +128,9 @@ def formatSize(num_of_bytes, precise=False):
except: # E.g. when filesize is hashed except: # E.g. when filesize is hashed
return "???" return "???"
def isASCII(s): def isASCII(s):
return all(ord(c) < 128 for c in s) return all(ord(c) < 128 for c in s)
def findResourcePath(resourceName): def findResourcePath(resourceName):
if resourceName == "syncplay.lua": if resourceName == "syncplay.lua":
resourcePath = os.path.join(findWorkingDir(), "lua", "intf" , "resources", resourceName) resourcePath = os.path.join(findWorkingDir(), "lua", "intf" , "resources", resourceName)
@ -152,7 +138,6 @@ def findResourcePath(resourceName):
resourcePath = os.path.join(findWorkingDir(),"resources", resourceName) resourcePath = os.path.join(findWorkingDir(),"resources", resourceName)
return resourcePath return resourcePath
def findWorkingDir(): def findWorkingDir():
frozen = getattr(sys, 'frozen', '') frozen = getattr(sys, 'frozen', '')
if not frozen: if not frozen:
@ -168,18 +153,15 @@ def findWorkingDir():
path = "" path = ""
return path return path
def getResourcesPath(): def getResourcesPath():
if isWindows(): if isWindows():
return findWorkingDir() + "\\resources\\" return findWorkingDir() + "\\resources\\"
else: else:
return findWorkingDir() + "/resources/" return findWorkingDir() + "/resources/"
resourcespath = getResourcesPath() resourcespath = getResourcesPath()
posixresourcespath = findWorkingDir().replace("\\","/") + "/resources/" posixresourcespath = findWorkingDir().replace("\\","/") + "/resources/"
def getDefaultMonospaceFont(): def getDefaultMonospaceFont():
if platform.system() == "Windows": if platform.system() == "Windows":
return constants.DEFAULT_WINDOWS_MONOSPACE_FONT return constants.DEFAULT_WINDOWS_MONOSPACE_FONT
@ -188,18 +170,15 @@ def getDefaultMonospaceFont():
else: else:
return constants.FALLBACK_MONOSPACE_FONT return constants.FALLBACK_MONOSPACE_FONT
def limitedPowerset(s, minLength): def limitedPowerset(s, minLength):
return itertools.chain.from_iterable(itertools.combinations(s, r) for r in range(len(s), minLength, -1)) return itertools.chain.from_iterable(itertools.combinations(s, r) for r in range(len(s), minLength, -1))
def blackholeStdoutForFrozenWindow(): def blackholeStdoutForFrozenWindow():
if getattr(sys, 'frozen', '') == "windows_exe": if getattr(sys, 'frozen', '') == "windows_exe":
class Stderr(object): class Stderr(object):
softspace = 0 softspace = 0
_file = None _file = None
_error = None _error = None
def write(self, text, fname='.syncplay.log'): def write(self, text, fname='.syncplay.log'):
if self._file is None and self._error is None: if self._file is None and self._error is None:
if os.name != 'nt': if os.name != 'nt':
@ -211,27 +190,21 @@ def blackholeStdoutForFrozenWindow():
if self._file is not None: if self._file is not None:
self._file.write(text) self._file.write(text)
self._file.flush() self._file.flush()
def flush(self): def flush(self):
if self._file is not None: if self._file is not None:
self._file.flush() self._file.flush()
sys.stderr = Stderr() sys.stderr = Stderr()
del Stderr del Stderr
class Blackhole(object): class Blackhole(object):
softspace = 0 softspace = 0
def write(self, text): def write(self, text):
pass pass
def flush(self): def flush(self):
pass pass
sys.stdout = Blackhole() sys.stdout = Blackhole()
del Blackhole del Blackhole
def truncateText(unicodeText, maxLength): def truncateText(unicodeText, maxLength):
try: try:
unicodeText = unicodeText.decode('utf-8') unicodeText = unicodeText.decode('utf-8')
@ -243,7 +216,6 @@ def truncateText(unicodeText, maxLength):
pass pass
return "" return ""
def splitText(unicodeText, maxLength): def splitText(unicodeText, maxLength):
try: try:
unicodeText = unicodeText.decode('utf-8') unicodeText = unicodeText.decode('utf-8')
@ -259,7 +231,6 @@ def splitText(unicodeText, maxLength):
# Relate to file hashing / difference checking: # Relate to file hashing / difference checking:
def stripfilename(filename, stripURL): def stripfilename(filename, stripURL):
if filename: if filename:
try: try:
@ -276,7 +247,6 @@ def stripfilename(filename, stripURL):
else: else:
return "" return ""
def stripRoomName(RoomName): def stripRoomName(RoomName):
if RoomName: if RoomName:
try: try:
@ -286,7 +256,6 @@ def stripRoomName(RoomName):
else: else:
return "" return ""
def hashFilename(filename, stripURL = False): def hashFilename(filename, stripURL = False):
if isURL(filename): if isURL(filename):
stripURL = True stripURL = True
@ -298,11 +267,9 @@ def hashFilename(filename, stripURL=False):
filenameHash = hashlib.sha256(strippedFilename).hexdigest()[:12] filenameHash = hashlib.sha256(strippedFilename).hexdigest()[:12]
return filenameHash return filenameHash
def hashFilesize(size): def hashFilesize(size):
return hashlib.sha256(str(size).encode('utf-8')).hexdigest()[:12] return hashlib.sha256(str(size).encode('utf-8')).hexdigest()[:12]
def sameHashed(string1raw, string1hashed, string2raw, string2hashed): def sameHashed(string1raw, string1hashed, string2raw, string2hashed):
try: try:
if string1raw.lower() == string2raw.lower(): if string1raw.lower() == string2raw.lower():
@ -318,7 +285,6 @@ def sameHashed(string1raw, string1hashed, string2raw, string2hashed):
elif string1hashed == string2hashed: elif string1hashed == string2hashed:
return True return True
def sameFilename (filename1, filename2): def sameFilename (filename1, filename2):
try: try:
filename1 = filename1 filename1 = filename1
@ -336,7 +302,6 @@ def sameFilename(filename1, filename2):
else: else:
return False return False
def sameFilesize (filesize1, filesize2): def sameFilesize (filesize1, filesize2):
if filesize1 == 0 or filesize2 == 0: if filesize1 == 0 or filesize2 == 0:
return True return True
@ -345,7 +310,6 @@ def sameFilesize(filesize1, filesize2):
else: else:
return False return False
def sameFileduration (duration1, duration2): def sameFileduration (duration1, duration2):
if not constants.SHOW_DURATION_NOTIFICATION: if not constants.SHOW_DURATION_NOTIFICATION:
return True return True
@ -354,13 +318,11 @@ def sameFileduration(duration1, duration2):
else: else:
return False return False
def meetsMinVersion(version, minVersion): def meetsMinVersion(version, minVersion):
def versiontotuple(ver): def versiontotuple(ver):
return tuple(map(int, ver.split("."))) return tuple(map(int, ver.split(".")))
return versiontotuple(version) >= versiontotuple(minVersion) return versiontotuple(version) >= versiontotuple(minVersion)
def isURL(path): def isURL(path):
if path is None: if path is None:
return False return False
@ -369,27 +331,22 @@ def isURL(path):
else: else:
return False return False
def getPlayerArgumentsByPathAsArray(arguments, path): def getPlayerArgumentsByPathAsArray(arguments, path):
if arguments and not isinstance(arguments, str) and path in arguments: if arguments and not isinstance(arguments, str) and path in arguments:
return arguments[path] return arguments[path]
else: else:
return None return None
def getPlayerArgumentsByPathAsText(arguments, path): def getPlayerArgumentsByPathAsText(arguments, path):
argsToReturn = getPlayerArgumentsByPathAsArray(arguments, path) argsToReturn = getPlayerArgumentsByPathAsArray(arguments, path)
return " ".join(argsToReturn) if argsToReturn else "" return " ".join(argsToReturn) if argsToReturn else ""
def getListAsMultilineString(pathArray): def getListAsMultilineString(pathArray):
return "\n".join(pathArray) if pathArray else "" return "\n".join(pathArray) if pathArray else ""
def convertMultilineStringToList(multilineString): def convertMultilineStringToList(multilineString):
return str.split(multilineString,"\n") if multilineString else "" return str.split(multilineString,"\n") if multilineString else ""
def playlistIsValid(files): def playlistIsValid(files):
if len(files) > constants.PLAYLIST_MAX_ITEMS: if len(files) > constants.PLAYLIST_MAX_ITEMS:
return False return False
@ -397,7 +354,6 @@ def playlistIsValid(files):
return False return False
return True return True
def getDomainFromURL(URL): def getDomainFromURL(URL):
try: try:
URL = URL.split("//")[-1].split("/")[0] URL = URL.split("//")[-1].split("/")[0]
@ -407,7 +363,6 @@ def getDomainFromURL(URL):
except: except:
return None return None
def open_system_file_browser(path): def open_system_file_browser(path):
if isURL(path): if isURL(path):
return return
@ -419,7 +374,6 @@ def open_system_file_browser(path):
else: else:
subprocess.Popen(["xdg-open", path]) subprocess.Popen(["xdg-open", path])
def getListOfPublicServers(): def getListOfPublicServers():
try: try:
import urllib.request, urllib.parse, urllib.error, syncplay, sys import urllib.request, urllib.parse, urllib.error, syncplay, sys
@ -440,13 +394,12 @@ def getListOfPublicServers():
else: else:
raise IOError raise IOError
except: except:
if constants.DEBUG_MODE: if constants.DEBUG_MODE == True:
traceback.print_exc() traceback.print_exc()
raise raise
else: else:
raise IOError(getMessage("failed-to-load-server-list-error")) raise IOError(getMessage("failed-to-load-server-list-error"))
class RoomPasswordProvider(object): class RoomPasswordProvider(object):
CONTROLLED_ROOM_REGEX = re.compile("^\+(.*):(\w{12})$") CONTROLLED_ROOM_REGEX = re.compile("^\+(.*):(\w{12})$")
PASSWORD_REGEX = re.compile("[A-Z]{2}-\d{3}-\d{3}") PASSWORD_REGEX = re.compile("[A-Z]{2}-\d{3}-\d{3}")
@ -480,7 +433,6 @@ class RoomPasswordProvider(object):
provisionalHash = hashlib.sha256(roomName + salt).hexdigest() provisionalHash = hashlib.sha256(roomName + salt).hexdigest()
return hashlib.sha1(provisionalHash + salt + password).hexdigest()[:12].upper() return hashlib.sha1(provisionalHash + salt + password).hexdigest()[:12].upper()
class RandomStringGenerator(object): class RandomStringGenerator(object):
@staticmethod @staticmethod
def generate_room_password(): def generate_room_password():
@ -506,6 +458,6 @@ class RandomStringGenerator(object):
def _get_random_numbers(quantity): def _get_random_numbers(quantity):
return ''.join(random.choice(string.digits) for _ in range(quantity)) return ''.join(random.choice(string.digits) for _ in range(quantity))
class NotControlledRoom(Exception): class NotControlledRoom(Exception):
pass pass

View File

@ -17,3 +17,4 @@ from syncplay.utils import blackholeStdoutForFrozenWindow
if __name__ == '__main__': if __name__ == '__main__':
blackholeStdoutForFrozenWindow() blackholeStdoutForFrozenWindow()
SyncplayClientManager().run() SyncplayClientManager().run()

View File

@ -19,14 +19,5 @@ from syncplay.server import SyncFactory, ConfigurationGetter
if __name__ == '__main__': if __name__ == '__main__':
argsGetter = ConfigurationGetter() argsGetter = ConfigurationGetter()
args = argsGetter.getConfiguration() args = argsGetter.getConfiguration()
reactor.listenTCP( reactor.listenTCP(int(args.port), SyncFactory(args.password, args.motd_file, args.isolate_rooms, args.salt, args.disable_ready,args.disable_chat, args.max_chat_message_length))
int(args.port),
SyncFactory(
args.password,
args.motd_file,
args.isolate_rooms,
args.salt,
args.disable_ready,
args.disable_chat,
args.max_chat_message_length))
reactor.run() reactor.run()