fix formattings
This commit is contained in:
parent
759f1e1457
commit
f01de206d8
23
appdmg.py
23
appdmg.py
@ -7,16 +7,18 @@ 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)
|
||||||
icon_name = plist['CFBundleIconFile']
|
icon_name = plist['CFBundleIconFile']
|
||||||
icon_root,icon_ext = os.path.splitext(icon_name)
|
icon_root, icon_ext = os.path.splitext(icon_name)
|
||||||
if not icon_ext:
|
if not icon_ext:
|
||||||
icon_ext = '.icns'
|
icon_ext = '.icns'
|
||||||
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')
|
||||||
|
|
||||||
@ -27,10 +29,19 @@ compression_level = 9
|
|||||||
size = defines.get('size', None)
|
size = defines.get('size', None)
|
||||||
|
|
||||||
# Files to include
|
# Files to include
|
||||||
files = [ application, 'resources/lua/intf/.syncplay.lua', 'resources/.macos_vlc_install.command', 'resources/.macOS_readme.pdf' ]
|
files = [
|
||||||
|
application,
|
||||||
|
'resources/lua/intf/.syncplay.lua',
|
||||||
|
'resources/.macos_vlc_install.command',
|
||||||
|
'resources/.macOS_readme.pdf'
|
||||||
|
]
|
||||||
|
|
||||||
# Symlinks to create
|
# Symlinks to create
|
||||||
symlinks = { 'Applications': '/Applications', 'Install for VLC': '.macos_vlc_install.command', 'Read Me': '.macOS_readme.pdf' }
|
symlinks = {
|
||||||
|
'Applications': '/Applications',
|
||||||
|
'Install for VLC': '.macos_vlc_install.command',
|
||||||
|
'Read Me': '.macOS_readme.pdf'
|
||||||
|
}
|
||||||
|
|
||||||
# Volume icon
|
# Volume icon
|
||||||
#
|
#
|
||||||
@ -38,12 +49,12 @@ symlinks = { 'Applications': '/Applications', 'Install for VLC': '.macos_vlc_ins
|
|||||||
# image, *or* you can define badge_icon, in which case the icon file you specify
|
# image, *or* you can define badge_icon, in which case the icon file you specify
|
||||||
# will be used to badge the system's Removable Disk icon
|
# will be used to badge the system's Removable Disk icon
|
||||||
#
|
#
|
||||||
#icon = '/path/to/icon.icns'
|
# icon = '/path/to/icon.icns'
|
||||||
badge_icon = icon_from_app(application)
|
badge_icon = icon_from_app(application)
|
||||||
|
|
||||||
# Where to put the icons
|
# Where to put the icons
|
||||||
icon_locations = {
|
icon_locations = {
|
||||||
appname: (150, 110),
|
appname: (150, 110),
|
||||||
'Applications': (450, 110),
|
'Applications': (450, 110),
|
||||||
'Read Me': (100, 285),
|
'Read Me': (100, 285),
|
||||||
'Install for VLC': (500, 285)
|
'Install for VLC': (500, 285)
|
||||||
@ -106,7 +117,7 @@ arrange_by = None
|
|||||||
grid_offset = (0, 0)
|
grid_offset = (0, 0)
|
||||||
grid_spacing = 20
|
grid_spacing = 20
|
||||||
scroll_position = (0, 0)
|
scroll_position = (0, 0)
|
||||||
label_pos = 'bottom' # or 'right'
|
label_pos = 'bottom' # or 'right'
|
||||||
text_size = 12
|
text_size = 12
|
||||||
icon_size = 80
|
icon_size = 80
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
#coding:utf8
|
# coding:utf8
|
||||||
|
|
||||||
|
|
||||||
#*** 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, 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!")
|
||||||
@ -14,18 +14,20 @@ import sys, codecs
|
|||||||
# 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
|
||||||
@ -39,9 +41,11 @@ 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 = "dist\Syncplay"
|
OUT_DIR = r"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
|
||||||
@ -79,7 +83,7 @@ NSIS_SCRIPT_TEMPLATE = r"""
|
|||||||
VIAddVersionKey /LANG=$${LANG_RUSSIAN} "FileVersion" "$version.0"
|
VIAddVersionKey /LANG=$${LANG_RUSSIAN} "FileVersion" "$version.0"
|
||||||
VIAddVersionKey /LANG=$${LANG_RUSSIAN} "LegalCopyright" "Syncplay"
|
VIAddVersionKey /LANG=$${LANG_RUSSIAN} "LegalCopyright" "Syncplay"
|
||||||
VIAddVersionKey /LANG=$${LANG_RUSSIAN} "FileDescription" "Syncplay"
|
VIAddVersionKey /LANG=$${LANG_RUSSIAN} "FileDescription" "Syncplay"
|
||||||
|
|
||||||
VIAddVersionKey /LANG=$${LANG_ITALIAN} "ProductName" "Syncplay"
|
VIAddVersionKey /LANG=$${LANG_ITALIAN} "ProductName" "Syncplay"
|
||||||
VIAddVersionKey /LANG=$${LANG_ITALIAN} "FileVersion" "$version.0"
|
VIAddVersionKey /LANG=$${LANG_ITALIAN} "FileVersion" "$version.0"
|
||||||
VIAddVersionKey /LANG=$${LANG_ITALIAN} "LegalCopyright" "Syncplay"
|
VIAddVersionKey /LANG=$${LANG_ITALIAN} "LegalCopyright" "Syncplay"
|
||||||
@ -127,7 +131,7 @@ NSIS_SCRIPT_TEMPLATE = r"""
|
|||||||
LangString ^QuickLaunchBar $${LANG_GERMAN} "Schnellstartleiste"
|
LangString ^QuickLaunchBar $${LANG_GERMAN} "Schnellstartleiste"
|
||||||
LangString ^AutomaticUpdates $${LANG_GERMAN} "Automatisch nach Updates suchen";
|
LangString ^AutomaticUpdates $${LANG_GERMAN} "Automatisch nach Updates suchen";
|
||||||
LangString ^UninstConfig $${LANG_GERMAN} "Konfigurationsdatei löschen."
|
LangString ^UninstConfig $${LANG_GERMAN} "Konfigurationsdatei löschen."
|
||||||
|
|
||||||
LangString ^SyncplayLanguage $${LANG_ITALIAN} "it"
|
LangString ^SyncplayLanguage $${LANG_ITALIAN} "it"
|
||||||
LangString ^Associate $${LANG_ITALIAN} "Associa Syncplay con i file multimediali."
|
LangString ^Associate $${LANG_ITALIAN} "Associa Syncplay con i file multimediali."
|
||||||
LangString ^VLC $${LANG_ITALIAN} "Installa l'interfaccia di Syncplay per VLC 2+"
|
LangString ^VLC $${LANG_ITALIAN} "Installa l'interfaccia di Syncplay per VLC 2+"
|
||||||
@ -241,11 +245,11 @@ NSIS_SCRIPT_TEMPLATE = r"""
|
|||||||
Push English
|
Push English
|
||||||
Push $${LANG_POLISH}
|
Push $${LANG_POLISH}
|
||||||
Push Polski
|
Push Polski
|
||||||
Push $${LANG_RUSSIAN}
|
Push $${LANG_RUSSIAN}
|
||||||
Push Русский
|
Push Русский
|
||||||
Push $${LANG_GERMAN}
|
Push $${LANG_GERMAN}
|
||||||
Push Deutsch
|
Push Deutsch
|
||||||
Push $${LANG_ITALIAN}
|
Push $${LANG_ITALIAN}
|
||||||
Push Italiano
|
Push Italiano
|
||||||
Push A ; A means auto count languages
|
Push A ; A means auto count languages
|
||||||
LangDLL::LangDialog "Language Selection" "Please select the language of Syncplay and the installer"
|
LangDLL::LangDialog "Language Selection" "Please select the language of Syncplay and the installer"
|
||||||
@ -317,25 +321,25 @@ NSIS_SCRIPT_TEMPLATE = r"""
|
|||||||
;$${EndIf}
|
;$${EndIf}
|
||||||
|
|
||||||
$${If} $$CheckBox_VLC_State == $${BST_CHECKED}
|
$${If} $$CheckBox_VLC_State == $${BST_CHECKED}
|
||||||
$${NSD_Check} $$CheckBox_VLC
|
$${NSD_Check} $$CheckBox_VLC
|
||||||
$${EndIf}
|
$${EndIf}
|
||||||
|
|
||||||
Call UpdateVLCCheckbox
|
Call UpdateVLCCheckbox
|
||||||
|
|
||||||
$${If} $$CheckBox_StartMenuShortcut_State == $${BST_CHECKED}
|
$${If} $$CheckBox_StartMenuShortcut_State == $${BST_CHECKED}
|
||||||
$${NSD_Check} $$CheckBox_StartMenuShortcut
|
$${NSD_Check} $$CheckBox_StartMenuShortcut
|
||||||
$${EndIf}
|
$${EndIf}
|
||||||
|
|
||||||
$${If} $$CheckBox_DesktopShortcut_State == $${BST_CHECKED}
|
$${If} $$CheckBox_DesktopShortcut_State == $${BST_CHECKED}
|
||||||
$${NSD_Check} $$CheckBox_DesktopShortcut
|
$${NSD_Check} $$CheckBox_DesktopShortcut
|
||||||
$${EndIf}
|
$${EndIf}
|
||||||
|
|
||||||
$${If} $$CheckBox_QuickLaunchShortcut_State == $${BST_CHECKED}
|
$${If} $$CheckBox_QuickLaunchShortcut_State == $${BST_CHECKED}
|
||||||
$${NSD_Check} $$CheckBox_QuickLaunchShortcut
|
$${NSD_Check} $$CheckBox_QuickLaunchShortcut
|
||||||
$${EndIf}
|
$${EndIf}
|
||||||
|
|
||||||
$${If} $$CheckBox_AutomaticUpdates_State == $${BST_CHECKED}
|
$${If} $$CheckBox_AutomaticUpdates_State == $${BST_CHECKED}
|
||||||
$${NSD_Check} $$CheckBox_AutomaticUpdates
|
$${NSD_Check} $$CheckBox_AutomaticUpdates
|
||||||
$${EndIf}
|
$${EndIf}
|
||||||
|
|
||||||
nsDialogs::Show
|
nsDialogs::Show
|
||||||
@ -608,24 +612,25 @@ 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)
|
||||||
print("Total size eq: {}".format(totalSize))
|
print("Total size eq: {}".format(totalSize))
|
||||||
installFiles = self.prepareInstallListTemplate(fileList)
|
installFiles = self.prepareInstallListTemplate(fileList)
|
||||||
uninstallFiles = self.prepareDeleteListTemplate(fileList)
|
uninstallFiles = self.prepareDeleteListTemplate(fileList)
|
||||||
|
|
||||||
if os.path.isfile(SETUP_SCRIPT_PATH):
|
if os.path.isfile(SETUP_SCRIPT_PATH):
|
||||||
raise RuntimeError("Cannot create setup script, file exists at {}".format(SETUP_SCRIPT_PATH))
|
raise RuntimeError("Cannot create setup script, file exists at {}".format(SETUP_SCRIPT_PATH))
|
||||||
contents = Template(NSIS_SCRIPT_TEMPLATE).substitute(
|
contents = Template(NSIS_SCRIPT_TEMPLATE).substitute(
|
||||||
version = syncplay.version,
|
version=syncplay.version,
|
||||||
uninstallFiles = uninstallFiles,
|
uninstallFiles=uninstallFiles,
|
||||||
installFiles = installFiles,
|
installFiles=installFiles,
|
||||||
totalSize = totalSize,
|
totalSize=totalSize,
|
||||||
)
|
)
|
||||||
with codecs.open(SETUP_SCRIPT_PATH, "w", "utf-8-sig") as outfile:
|
with codecs.open(SETUP_SCRIPT_PATH, "w", "utf-8-sig") as outfile:
|
||||||
outfile.write(contents)
|
outfile.write(contents)
|
||||||
|
|
||||||
def compile(self):
|
def compile(self):
|
||||||
if not os.path.isfile(NSIS_COMPILE):
|
if not os.path.isfile(NSIS_COMPILE):
|
||||||
return "makensis.exe not found, won't create the installer"
|
return "makensis.exe not found, won't create the installer"
|
||||||
@ -635,7 +640,7 @@ class NSISScript(object):
|
|||||||
os.remove(SETUP_SCRIPT_PATH)
|
os.remove(SETUP_SCRIPT_PATH)
|
||||||
if retcode:
|
if retcode:
|
||||||
raise RuntimeError("NSIS compilation return code: %d" % retcode)
|
raise RuntimeError("NSIS compilation return code: %d" % retcode)
|
||||||
|
|
||||||
def getBuildDirContents(self, path):
|
def getBuildDirContents(self, path):
|
||||||
fileList = {}
|
fileList = {}
|
||||||
totalSize = 0
|
totalSize = 0
|
||||||
@ -646,8 +651,8 @@ class NSISScript(object):
|
|||||||
if new_root not in fileList:
|
if new_root not in fileList:
|
||||||
fileList[new_root] = []
|
fileList[new_root] = []
|
||||||
fileList[new_root].append(file_)
|
fileList[new_root].append(file_)
|
||||||
return fileList, totalSize
|
return fileList, totalSize
|
||||||
|
|
||||||
def prepareInstallListTemplate(self, fileList):
|
def prepareInstallListTemplate(self, fileList):
|
||||||
create = []
|
create = []
|
||||||
for dir_ in fileList.keys():
|
for dir_ in fileList.keys():
|
||||||
@ -655,38 +660,46 @@ class NSISScript(object):
|
|||||||
for file_ in fileList[dir_]:
|
for file_ in fileList[dir_]:
|
||||||
create.append('FILE "{}\\{}\\{}"'.format(OUT_DIR, dir_, file_))
|
create.append('FILE "{}\\{}\\{}"'.format(OUT_DIR, dir_, file_))
|
||||||
return "\n".join(create)
|
return "\n".join(create)
|
||||||
|
|
||||||
def prepareDeleteListTemplate(self, fileList):
|
def prepareDeleteListTemplate(self, fileList):
|
||||||
delete = []
|
delete = []
|
||||||
for dir_ in fileList.keys():
|
for dir_ in fileList.keys():
|
||||||
for file_ in fileList[dir_]:
|
for file_ in fileList[dir_]:
|
||||||
delete.append('DELETE "$INSTDIR\\{}\\{}"'.format(dir_, file_))
|
delete.append('DELETE "$INSTDIR\\{}\\{}"'.format(dir_, file_))
|
||||||
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',
|
|
||||||
'resources/control_pause_blue.png', 'resources/cross.png', 'resources/door_in.png',
|
guiIcons = [
|
||||||
'resources/folder_explore.png', 'resources/help.png', 'resources/table_refresh.png',
|
'resources/accept.png', 'resources/arrow_undo.png', 'resources/clock_go.png',
|
||||||
'resources/timeline_marker.png','resources/control_play_blue.png',
|
'resources/control_pause_blue.png', 'resources/cross.png', 'resources/door_in.png',
|
||||||
'resources/mpc-hc.png','resources/mpc-hc64.png','resources/mplayer.png',
|
'resources/folder_explore.png', 'resources/help.png', 'resources/table_refresh.png',
|
||||||
'resources/mpc-be.png',
|
'resources/timeline_marker.png', 'resources/control_play_blue.png',
|
||||||
'resources/mpv.png','resources/vlc.png', 'resources/house.png', 'resources/film_link.png',
|
'resources/mpc-hc.png', 'resources/mpc-hc64.png', 'resources/mplayer.png',
|
||||||
'resources/eye.png', 'resources/comments.png', 'resources/cog_delete.png', 'resources/chevrons_right.png',
|
'resources/mpc-be.png',
|
||||||
'resources/user_key.png', 'resources/lock.png', 'resources/key_go.png', 'resources/page_white_key.png',
|
'resources/mpv.png', 'resources/vlc.png', 'resources/house.png', 'resources/film_link.png',
|
||||||
'resources/tick.png', 'resources/lock_open.png', 'resources/empty_checkbox.png', 'resources/tick_checkbox.png',
|
'resources/eye.png', 'resources/comments.png', 'resources/cog_delete.png', 'resources/chevrons_right.png',
|
||||||
'resources/world_explore.png', 'resources/application_get.png', 'resources/cog.png', 'resources/arrow_switch.png',
|
'resources/user_key.png', 'resources/lock.png', 'resources/key_go.png', 'resources/page_white_key.png',
|
||||||
'resources/film_go.png', 'resources/world_go.png', 'resources/arrow_refresh.png', 'resources/bullet_right_grey.png',
|
'resources/tick.png', 'resources/lock_open.png', 'resources/empty_checkbox.png', 'resources/tick_checkbox.png',
|
||||||
'resources/user_comment.png',
|
'resources/world_explore.png', 'resources/application_get.png', 'resources/cog.png', 'resources/arrow_switch.png',
|
||||||
'resources/error.png',
|
'resources/film_go.png', 'resources/world_go.png', 'resources/arrow_refresh.png', 'resources/bullet_right_grey.png',
|
||||||
'resources/film_folder_edit.png',
|
'resources/user_comment.png',
|
||||||
'resources/film_edit.png',
|
'resources/error.png',
|
||||||
'resources/folder_film.png',
|
'resources/film_folder_edit.png',
|
||||||
'resources/shield_edit.png',
|
'resources/film_edit.png',
|
||||||
'resources/shield_add.png',
|
'resources/folder_film.png',
|
||||||
'resources/email_go.png',
|
'resources/shield_edit.png',
|
||||||
'resources/world_add.png', 'resources/film_add.png', 'resources/delete.png', 'resources/spinner.mng'
|
'resources/shield_add.png',
|
||||||
]
|
'resources/email_go.png',
|
||||||
resources = ["resources/icon.ico", "resources/syncplay.png", "resources/syncplayintf.lua", "resources/license.rtf", "resources/third-party-notices.rtf"]
|
'resources/world_add.png', 'resources/film_add.png', 'resources/delete.png', 'resources/spinner.mng'
|
||||||
|
]
|
||||||
|
resources = [
|
||||||
|
"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"]
|
||||||
|
|
||||||
@ -697,7 +710,7 @@ common_info = dict(
|
|||||||
author_email='dev@syncplay.pl',
|
author_email='dev@syncplay.pl',
|
||||||
description='Syncplay',
|
description='Syncplay',
|
||||||
)
|
)
|
||||||
|
|
||||||
script = NSISScript()
|
script = NSISScript()
|
||||||
script.create()
|
script.create()
|
||||||
print("*** compiling the NSIS setup script***")
|
print("*** compiling the NSIS setup script***")
|
||||||
|
|||||||
@ -14,16 +14,21 @@ DATA_FILES = [
|
|||||||
('resources', glob('resources/*.png') + glob('resources/*.rtf') + glob('resources/*.lua')),
|
('resources', glob('resources/*.png') + glob('resources/*.rtf') + glob('resources/*.lua')),
|
||||||
]
|
]
|
||||||
OPTIONS = {
|
OPTIONS = {
|
||||||
'iconfile':'resources/icon.icns',
|
'iconfile': 'resources/icon.icns',
|
||||||
'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': ['platforms/libqcocoa.dylib', 'platforms/libqminimal.dylib','platforms/libqoffscreen.dylib', 'styles/libqmacstyle.dylib'],
|
'qt_plugins': [
|
||||||
|
'platforms/libqcocoa.dylib',
|
||||||
|
'platforms/libqminimal.dylib',
|
||||||
|
'platforms/libqoffscreen.dylib',
|
||||||
|
'styles/libqmacstyle.dylib'
|
||||||
|
],
|
||||||
'plist': {
|
'plist': {
|
||||||
'CFBundleName':'Syncplay',
|
'CFBundleName': 'Syncplay',
|
||||||
'CFBundleShortVersionString':syncplay.version,
|
'CFBundleShortVersionString': syncplay.version,
|
||||||
'CFBundleIdentifier':'pl.syncplay.Syncplay',
|
'CFBundleIdentifier': 'pl.syncplay.Syncplay',
|
||||||
'LSMinimumSystemVersion':'10.11.0',
|
'LSMinimumSystemVersion': '10.11.0',
|
||||||
'NSHumanReadableCopyright': '@ 2018 Syncplay All Rights Reserved'
|
'NSHumanReadableCopyright': '@ 2018 Syncplay All Rights Reserved'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,13 +4,14 @@ from syncplay.players.vlc import VlcPlayer
|
|||||||
try:
|
try:
|
||||||
from syncplay.players.mpc import MPCHCAPIPlayer
|
from syncplay.players.mpc import MPCHCAPIPlayer
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from syncplay.players.basePlayer import DummyPlayer
|
from syncplay.players.basePlayer import DummyPlayer
|
||||||
MPCHCAPIPlayer = DummyPlayer
|
MPCHCAPIPlayer = DummyPlayer
|
||||||
try:
|
try:
|
||||||
from syncplay.players.mpcbe import MpcBePlayer
|
from syncplay.players.mpcbe import MpcBePlayer
|
||||||
except ImportError:
|
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]
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
from syncplay import constants
|
from syncplay import constants
|
||||||
|
|
||||||
|
|
||||||
class BasePlayer(object):
|
class BasePlayer(object):
|
||||||
|
|
||||||
'''
|
'''
|
||||||
This method is supposed to
|
This method is supposed to
|
||||||
execute updatePlayerStatus(paused, position) on client
|
execute updatePlayerStatus(paused, position) on client
|
||||||
Given the arguments: boolean paused and float position in seconds
|
Given the arguments: boolean paused and float position in seconds
|
||||||
'''
|
'''
|
||||||
def askForStatus(self):
|
def askForStatus(self):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
@ -12,7 +14,9 @@ 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(self, message, duration = (constants.OSD_DURATION*1000), secondaryOSD=False, mood=constants.MESSAGE_NEUTRAL):
|
def displayMessage(
|
||||||
|
self, message, duration=(constants.OSD_DURATION*1000), secondaryOSD=False, mood=constants.MESSAGE_NEUTRAL
|
||||||
|
):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
'''
|
'''
|
||||||
@ -29,62 +33,61 @@ class BasePlayer(object):
|
|||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
'''
|
'''
|
||||||
@type value: boolean
|
@type value: boolean
|
||||||
'''
|
'''
|
||||||
def setPaused(self, value):
|
def setPaused(self, value):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
'''
|
'''
|
||||||
@type value: list
|
@type value: list
|
||||||
'''
|
'''
|
||||||
def setFeatures(self, featureList):
|
def setFeatures(self, featureList):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
'''
|
'''
|
||||||
@type value: float
|
@type value: float
|
||||||
'''
|
'''
|
||||||
def setPosition(self, value):
|
def setPosition(self, value):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
'''
|
'''
|
||||||
@type value: float
|
@type value: float
|
||||||
'''
|
'''
|
||||||
def setSpeed(self, value):
|
def setSpeed(self, value):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
'''
|
'''
|
||||||
@type filePath: string
|
@type filePath: string
|
||||||
'''
|
'''
|
||||||
def openFile(self, filePath, resetPosition=False):
|
def openFile(self, filePath, resetPosition=False):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
@return: list of strings
|
@return: list of strings
|
||||||
'''
|
'''
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def getDefaultPlayerPathsList():
|
def getDefaultPlayerPathsList():
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
'''
|
'''
|
||||||
@type path: string
|
@type path: string
|
||||||
'''
|
'''
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def isValidPlayerPath(path):
|
def isValidPlayerPath(path):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
'''
|
'''
|
||||||
@type path: string
|
@type path: string
|
||||||
@return: string
|
@return: string
|
||||||
'''
|
'''
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def getIconPath(path):
|
def getIconPath(path):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
'''
|
'''
|
||||||
@type path: string
|
@type path: string
|
||||||
@return: string
|
@return: string
|
||||||
'''
|
'''
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def getExpandedPath(path):
|
def getExpandedPath(path):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
@ -107,24 +110,25 @@ class BasePlayer(object):
|
|||||||
def getPlayerPathErrors(playerPath, filePath):
|
def getPlayerPathErrors(playerPath, filePath):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
class DummyPlayer(BasePlayer):
|
class DummyPlayer(BasePlayer):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def getDefaultPlayerPathsList():
|
def getDefaultPlayerPathsList():
|
||||||
return []
|
return []
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def isValidPlayerPath(path):
|
def isValidPlayerPath(path):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def getIconPath(path):
|
def getIconPath(path):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def getExpandedPath(path):
|
def getExpandedPath(path):
|
||||||
return path
|
return path
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def getPlayerPathErrors(playerPath, filePath):
|
def getPlayerPathErrors(playerPath, filePath):
|
||||||
return None
|
return None
|
||||||
|
|||||||
@ -1,15 +1,18 @@
|
|||||||
#coding:utf8
|
|
||||||
|
import os.path
|
||||||
|
import re
|
||||||
import time
|
import time
|
||||||
import threading
|
import threading
|
||||||
import _thread
|
import _thread
|
||||||
import win32con, win32api, win32gui, ctypes, ctypes.wintypes #@UnresolvedImport @UnusedImport
|
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from syncplay.players.basePlayer import BasePlayer
|
|
||||||
import re
|
import win32con, win32api, win32gui, ctypes, ctypes.wintypes #@UnresolvedImport @UnusedImport
|
||||||
from syncplay.utils import retry
|
|
||||||
from syncplay import constants
|
from syncplay import constants
|
||||||
from syncplay.messages import getMessage
|
from syncplay.messages import getMessage
|
||||||
import os.path
|
from syncplay.players.basePlayer import BasePlayer
|
||||||
|
from syncplay.utils import retry
|
||||||
|
|
||||||
|
|
||||||
class MpcHcApi:
|
class MpcHcApi:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -30,7 +33,7 @@ class MpcHcApi:
|
|||||||
self.__listener.start()
|
self.__listener.start()
|
||||||
self.__locks.listenerStart.wait()
|
self.__locks.listenerStart.wait()
|
||||||
|
|
||||||
def waitForFileStateReady(f): #@NoSelf
|
def waitForFileStateReady(f): #@NoSelf
|
||||||
@wraps(f)
|
@wraps(f)
|
||||||
def wrapper(self, *args, **kwds):
|
def wrapper(self, *args, **kwds):
|
||||||
if not self.__locks.fileReady.wait(constants.MPC_LOCK_WAIT_TIME):
|
if not self.__locks.fileReady.wait(constants.MPC_LOCK_WAIT_TIME):
|
||||||
@ -49,7 +52,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 != None
|
return self.playState != self.__MPC_PLAYSTATE.PS_PLAY and self.playState is not None
|
||||||
|
|
||||||
def askForVersion(self):
|
def askForVersion(self):
|
||||||
self.__listener.SendCommand(self.CMD_GETVERSION)
|
self.__listener.SendCommand(self.CMD_GETVERSION)
|
||||||
@ -99,18 +102,22 @@ class MpcHcApi:
|
|||||||
self.__listener.mpcHandle = int(value)
|
self.__listener.mpcHandle = int(value)
|
||||||
self.__locks.mpcStart.set()
|
self.__locks.mpcStart.set()
|
||||||
if self.callbacks.onConnected:
|
if self.callbacks.onConnected:
|
||||||
_thread.start_new_thread(self.callbacks.onConnected, ())
|
_thread.start_new_thread(self.callbacks.onConnected, ())
|
||||||
|
|
||||||
elif cmd == self.CMD_STATE:
|
elif cmd == self.CMD_STATE:
|
||||||
self.loadState = int(value)
|
self.loadState = int(value)
|
||||||
fileNotReady = self.loadState == self.__MPC_LOADSTATE.MLS_CLOSING or self.loadState == self.__MPC_LOADSTATE.MLS_LOADING or self.loadState == self.__MPC_LOADSTATE.MLS_CLOSED
|
fileNotReady = (
|
||||||
|
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()
|
||||||
else:
|
else:
|
||||||
self.__locks.fileReady.set()
|
self.__locks.fileReady.set()
|
||||||
if self.callbacks.onFileStateChange:
|
if self.callbacks.onFileStateChange:
|
||||||
_thread.start_new_thread(self.callbacks.onFileStateChange, (self.loadState,))
|
_thread.start_new_thread(self.callbacks.onFileStateChange, (self.loadState,))
|
||||||
|
|
||||||
elif cmd == self.CMD_PLAYMODE:
|
elif cmd == self.CMD_PLAYMODE:
|
||||||
self.playState = int(value)
|
self.playState = int(value)
|
||||||
@ -125,31 +132,31 @@ class MpcHcApi:
|
|||||||
self.filePlaying = value[3].split('\\').pop()
|
self.filePlaying = value[3].split('\\').pop()
|
||||||
self.fileDuration = float(value[4])
|
self.fileDuration = float(value[4])
|
||||||
if self.callbacks.onUpdatePath:
|
if self.callbacks.onUpdatePath:
|
||||||
_thread.start_new_thread(self.callbacks.onUpdatePath, (self.onUpdatePath,))
|
_thread.start_new_thread(self.callbacks.onUpdatePath, (self.onUpdatePath,))
|
||||||
if self.callbacks.onUpdateFilename:
|
if self.callbacks.onUpdateFilename:
|
||||||
_thread.start_new_thread(self.callbacks.onUpdateFilename, (self.filePlaying,))
|
_thread.start_new_thread(self.callbacks.onUpdateFilename, (self.filePlaying,))
|
||||||
if self.callbacks.onUpdateFileDuration:
|
if self.callbacks.onUpdateFileDuration:
|
||||||
_thread.start_new_thread(self.callbacks.onUpdateFileDuration, (self.fileDuration,))
|
_thread.start_new_thread(self.callbacks.onUpdateFileDuration, (self.fileDuration,))
|
||||||
|
|
||||||
elif cmd == self.CMD_CURRENTPOSITION:
|
elif cmd == self.CMD_CURRENTPOSITION:
|
||||||
self.lastFilePosition = float(value)
|
self.lastFilePosition = float(value)
|
||||||
if self.callbacks.onGetCurrentPosition:
|
if self.callbacks.onGetCurrentPosition:
|
||||||
_thread.start_new_thread(self.callbacks.onGetCurrentPosition, (self.lastFilePosition,))
|
_thread.start_new_thread(self.callbacks.onGetCurrentPosition, (self.lastFilePosition,))
|
||||||
|
|
||||||
elif cmd == self.CMD_NOTIFYSEEK:
|
elif cmd == self.CMD_NOTIFYSEEK:
|
||||||
if self.lastFilePosition != float(value): #Notify seek is sometimes sent twice
|
if self.lastFilePosition != float(value): # Notify seek is sometimes sent twice
|
||||||
self.lastFilePosition = float(value)
|
self.lastFilePosition = float(value)
|
||||||
if self.callbacks.onSeek:
|
if self.callbacks.onSeek:
|
||||||
_thread.start_new_thread(self.callbacks.onSeek, (self.lastFilePosition,))
|
_thread.start_new_thread(self.callbacks.onSeek, (self.lastFilePosition,))
|
||||||
|
|
||||||
elif cmd == self.CMD_DISCONNECT:
|
elif cmd == self.CMD_DISCONNECT:
|
||||||
if self.callbacks.onMpcClosed:
|
if self.callbacks.onMpcClosed:
|
||||||
_thread.start_new_thread(self.callbacks.onMpcClosed, (None,))
|
_thread.start_new_thread(self.callbacks.onMpcClosed, (None,))
|
||||||
|
|
||||||
elif cmd == self.CMD_VERSION:
|
elif cmd == self.CMD_VERSION:
|
||||||
if self.callbacks.onVersion:
|
if self.callbacks.onVersion:
|
||||||
self.version = value
|
self.version = value
|
||||||
_thread.start_new_thread(self.callbacks.onVersion, (value,))
|
_thread.start_new_thread(self.callbacks.onVersion, (value,))
|
||||||
|
|
||||||
class PlayerNotReadyException(Exception):
|
class PlayerNotReadyException(Exception):
|
||||||
pass
|
pass
|
||||||
@ -198,11 +205,11 @@ class MpcHcApi:
|
|||||||
CMD_ADDTOPLAYLIST = 0xA0001000
|
CMD_ADDTOPLAYLIST = 0xA0001000
|
||||||
CMD_CLEARPLAYLIST = 0xA0001001
|
CMD_CLEARPLAYLIST = 0xA0001001
|
||||||
CMD_STARTPLAYLIST = 0xA0001002
|
CMD_STARTPLAYLIST = 0xA0001002
|
||||||
CMD_REMOVEFROMPLAYLIST = 0xA0001003 # TODO
|
CMD_REMOVEFROMPLAYLIST = 0xA0001003 # TODO
|
||||||
CMD_SETPOSITION = 0xA0002000
|
CMD_SETPOSITION = 0xA0002000
|
||||||
CMD_SETAUDIODELAY = 0xA0002001
|
CMD_SETAUDIODELAY = 0xA0002001
|
||||||
CMD_SETSUBTITLEDELAY = 0xA0002002
|
CMD_SETSUBTITLEDELAY = 0xA0002002
|
||||||
CMD_SETINDEXPLAYLIST = 0xA0002003 # DOESNT WORK
|
CMD_SETINDEXPLAYLIST = 0xA0002003 # DOESNT WORK
|
||||||
CMD_SETAUDIOTRACK = 0xA0002004
|
CMD_SETAUDIOTRACK = 0xA0002004
|
||||||
CMD_SETSUBTITLETRACK = 0xA0002005
|
CMD_SETSUBTITLETRACK = 0xA0002005
|
||||||
CMD_GETSUBTITLETRACKS = 0xA0003000
|
CMD_GETSUBTITLETRACKS = 0xA0003000
|
||||||
@ -256,7 +263,7 @@ class MpcHcApi:
|
|||||||
wc.lpszClassName = 'MPCApiListener'
|
wc.lpszClassName = 'MPCApiListener'
|
||||||
hinst = wc.hInstance = win32api.GetModuleHandle(None)
|
hinst = wc.hInstance = win32api.GetModuleHandle(None)
|
||||||
classAtom = win32gui.RegisterClass(wc)
|
classAtom = win32gui.RegisterClass(wc)
|
||||||
self.hwnd = win32gui.CreateWindow (
|
self.hwnd = win32gui.CreateWindow(
|
||||||
classAtom,
|
classAtom,
|
||||||
"ListenerGUI",
|
"ListenerGUI",
|
||||||
0,
|
0,
|
||||||
@ -272,14 +279,13 @@ 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)
|
||||||
self.__mpcApi.handleCommand(pCDS.contents.dwData, ctypes.wstring_at(pCDS.contents.lpData))
|
self.__mpcApi.handleCommand(pCDS.contents.dwData, ctypes.wstring_at(pCDS.contents.lpData))
|
||||||
|
|
||||||
def SendCommand(self, cmd, message=''):
|
def SendCommand(self, cmd, message=''):
|
||||||
#print "API:\t<out\t 0x%X\t" % int(cmd), message
|
# print "API:\t<out\t 0x%X\t" % int(cmd), message
|
||||||
if not win32gui.IsWindow(self.mpcHandle):
|
if not win32gui.IsWindow(self.mpcHandle):
|
||||||
if self.__mpcApi.callbacks.onMpcClosed:
|
if self.__mpcApi.callbacks.onMpcClosed:
|
||||||
self.__mpcApi.callbacks.onMpcClosed(None)
|
self.__mpcApi.callbacks.onMpcClosed(None)
|
||||||
@ -304,6 +310,7 @@ 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
|
||||||
@ -400,7 +407,10 @@ 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(self, message, duration = (constants.OSD_DURATION*1000), OSDType=constants.OSD_NOTIFICATION, mood=constants.MESSAGE_NEUTRAL):
|
def displayMessage(
|
||||||
|
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)
|
||||||
@ -412,6 +422,7 @@ 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
|
||||||
|
|
||||||
@ -482,7 +493,10 @@ class MPCHCAPIPlayer(BasePlayer):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def getIconPath(path):
|
def getIconPath(path):
|
||||||
if MPCHCAPIPlayer.getExpandedPath(path).lower().endswith('mpc-hc64.exe'.lower()) or MPCHCAPIPlayer.getExpandedPath(path).lower().endswith('mpc-hc64_nvo.exe'.lower()):
|
if (
|
||||||
|
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
|
||||||
@ -496,7 +510,11 @@ class MPCHCAPIPlayer(BasePlayer):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def getExpandedPath(path):
|
def getExpandedPath(path):
|
||||||
if os.path.isfile(path):
|
if os.path.isfile(path):
|
||||||
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()):
|
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())
|
||||||
|
):
|
||||||
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"
|
||||||
@ -528,4 +546,3 @@ 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
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
from syncplay import constants
|
|
||||||
import os.path
|
import os.path
|
||||||
|
|
||||||
|
from syncplay import constants
|
||||||
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):
|
||||||
@ -30,7 +33,11 @@ class MpcBePlayer(MPCHCAPIPlayer):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def getExpandedPath(path):
|
def getExpandedPath(path):
|
||||||
if os.path.isfile(path):
|
if os.path.isfile(path):
|
||||||
if path.lower().endswith('mpc-be.exe'.lower()) or path.lower().endswith('mpc-be64.exe'.lower() or path.lower().endswith('mpc-beportable.exe'.lower())):
|
if (
|
||||||
|
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"
|
||||||
|
|||||||
@ -1,14 +1,18 @@
|
|||||||
# coding:utf8
|
# coding:utf8
|
||||||
import subprocess
|
import os
|
||||||
import re
|
import re
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
from syncplay.players.basePlayer import BasePlayer
|
|
||||||
|
|
||||||
from syncplay import constants, utils
|
from syncplay import constants, utils
|
||||||
|
from syncplay.players.basePlayer import BasePlayer
|
||||||
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
|
||||||
@ -90,15 +94,20 @@ 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(self, message, duration=(constants.OSD_DURATION * 1000), OSDType=constants.OSD_NOTIFICATION, mood=constants.MESSAGE_NEUTRAL):
|
def displayMessage(
|
||||||
|
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.OSD_QUERY, messageString, duration, constants.MPLAYER_OSD_LEVEL))
|
self._listener.sendLine('{} "{!s}" {} {}'.format(
|
||||||
|
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.OSD_QUERY, messageString, duration, constants.MPLAYER_OSD_LEVEL))
|
self._listener.sendLine('{} "{!s}" {} {}'.format(
|
||||||
|
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))
|
||||||
@ -118,7 +127,7 @@ class MplayerPlayer(BasePlayer):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def setPosition(self, value):
|
def setPosition(self, value):
|
||||||
self._position = max(value,0)
|
self._position = max(value, 0)
|
||||||
self._setProperty(self.POSITION_QUERY, "{}".format(value))
|
self._setProperty(self.POSITION_QUERY, "{}".format(value))
|
||||||
time.sleep(0.03)
|
time.sleep(0.03)
|
||||||
|
|
||||||
@ -151,7 +160,7 @@ class MplayerPlayer(BasePlayer):
|
|||||||
text = text.replace("\\", "\\\\")
|
text = text.replace("\\", "\\\\")
|
||||||
text = text.replace("{", "\\\\{")
|
text = text.replace("{", "\\\\{")
|
||||||
text = text.replace("}", "\\\\}")
|
text = text.replace("}", "\\\\}")
|
||||||
text = text.replace("<SYNCPLAY_QUOTE>","\\\"")
|
text = text.replace("<SYNCPLAY_QUOTE>", "\\\"")
|
||||||
return text
|
return text
|
||||||
|
|
||||||
def _quoteArg(self, arg):
|
def _quoteArg(self, arg):
|
||||||
@ -169,7 +178,7 @@ class MplayerPlayer(BasePlayer):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def _storePosition(self, value):
|
def _storePosition(self, value):
|
||||||
self._position = max(value,0)
|
self._position = max(value, 0)
|
||||||
|
|
||||||
def _storePauseState(self, value):
|
def _storePauseState(self, value):
|
||||||
self._paused = value
|
self._paused = value
|
||||||
@ -179,9 +188,15 @@ class MplayerPlayer(BasePlayer):
|
|||||||
self._client.ui.showDebugMessage("player << {}".format(line))
|
self._client.ui.showDebugMessage("player << {}".format(line))
|
||||||
line = line.replace("[cplayer] ", "") # -v workaround
|
line = line.replace("[cplayer] ", "") # -v workaround
|
||||||
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 "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 (
|
||||||
|
"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:
|
||||||
@ -194,7 +209,7 @@ class MplayerPlayer(BasePlayer):
|
|||||||
self._handleUnknownLine(line)
|
self._handleUnknownLine(line)
|
||||||
return
|
return
|
||||||
|
|
||||||
name, value =[m for m in match.groups() if m]
|
name, value = [m for m in match.groups() if m]
|
||||||
name = name.lower()
|
name = name.lower()
|
||||||
|
|
||||||
if name == self.POSITION_QUERY:
|
if name == self.POSITION_QUERY:
|
||||||
@ -250,7 +265,7 @@ class MplayerPlayer(BasePlayer):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def isValidPlayerPath(path):
|
def isValidPlayerPath(path):
|
||||||
if "mplayer" in path and MplayerPlayer.getExpandedPath(path) and not "mplayerc.exe" in path: # "mplayerc.exe" is Media Player Classic (not Home Cinema):
|
if "mplayer" in path and MplayerPlayer.getExpandedPath(path) and "mplayerc.exe" not in path: # "mplayerc.exe" is Media Player Classic (not Home Cinema):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -301,7 +316,7 @@ class MplayerPlayer(BasePlayer):
|
|||||||
if not self.__playerController._client._config["chatOutputEnabled"]:
|
if not self.__playerController._client._config["chatOutputEnabled"]:
|
||||||
self.__playerController.alertOSDSupported = False
|
self.__playerController.alertOSDSupported = False
|
||||||
self.__playerController.chatOSDSupported = False
|
self.__playerController.chatOSDSupported = False
|
||||||
if self.__playerController.getPlayerPathErrors(playerPath,filePath):
|
if self.__playerController.getPlayerPathErrors(playerPath, filePath):
|
||||||
raise ValueError()
|
raise ValueError()
|
||||||
if filePath and '://' not in filePath:
|
if filePath and '://' not in filePath:
|
||||||
if not os.path.isfile(filePath) and 'PWD' in os.environ:
|
if not os.path.isfile(filePath) and 'PWD' in os.environ:
|
||||||
@ -324,12 +339,15 @@ 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(call, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=self.__getCwd(filePath, env), env=env, bufsize=0)
|
self.__process = subprocess.Popen(
|
||||||
|
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(call, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT, env=env, bufsize=0)
|
self.__process = subprocess.Popen(
|
||||||
|
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
|
||||||
@ -365,8 +383,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._client.ui.executeCommand,
|
self.__playerController.reactor.callFromThread(
|
||||||
command)
|
self.__playerController._client.ui.executeCommand, command)
|
||||||
return
|
return
|
||||||
self.__playerController.reactor.callFromThread(self.__playerController._client.sendChat, message)
|
self.__playerController.reactor.callFromThread(self.__playerController._client.sendChat, message)
|
||||||
|
|
||||||
@ -377,12 +395,12 @@ class MplayerPlayer(BasePlayer):
|
|||||||
def setReadyToSend(self, newReadyState):
|
def setReadyToSend(self, newReadyState):
|
||||||
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 not newReadyState else None
|
||||||
if self.readyToSend == True:
|
if self.readyToSend:
|
||||||
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 == True and oldState == False:
|
if self.readyToSend and not oldState:
|
||||||
self.processSendQueue()
|
self.processSendQueue()
|
||||||
|
|
||||||
def checkForReadinessOverride(self):
|
def checkForReadinessOverride(self):
|
||||||
@ -391,7 +409,7 @@ class MplayerPlayer(BasePlayer):
|
|||||||
|
|
||||||
def sendLine(self, line, notReadyAfterThis=None):
|
def sendLine(self, line, notReadyAfterThis=None):
|
||||||
self.checkForReadinessOverride()
|
self.checkForReadinessOverride()
|
||||||
if self.readyToSend == False and "print_text ANS_pause" in line:
|
if not self.readyToSend 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:
|
||||||
@ -401,11 +419,13 @@ 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("<mpv> Remove duplicate (supersede): {}".format(self.sendQueue[itemID]))
|
self.__playerController._client.ui.showDebugMessage(
|
||||||
|
"<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("<mpv> Unicode mismatch occured when trying to remove duplicate")
|
self.__playerController._client.ui.showDebugMessage(
|
||||||
|
"<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
|
||||||
@ -415,7 +435,8 @@ 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("<mpv> Remove duplicate (delete both): {}".format(self.sendQueue[itemID]))
|
self.__playerController._client.ui.showDebugMessage(
|
||||||
|
"<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:
|
||||||
@ -428,7 +449,9 @@ 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("<mpv> Throttling message send, so sleeping for {}".format(constants.MPV_SENDMESSAGE_COOLDOWN_TIME))
|
self.__playerController._client.ui.showDebugMessage(
|
||||||
|
"<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()
|
||||||
@ -440,8 +463,8 @@ class MplayerPlayer(BasePlayer):
|
|||||||
|
|
||||||
def actuallySendLine(self, line):
|
def actuallySendLine(self, line):
|
||||||
try:
|
try:
|
||||||
#if not isinstance(line, str):
|
# if not isinstance(line, str):
|
||||||
#line = line.decode('utf8')
|
# line = line.decode('utf8')
|
||||||
line = line + "\n"
|
line = line + "\n"
|
||||||
self.__playerController._client.ui.showDebugMessage("player >> {}".format(line))
|
self.__playerController._client.ui.showDebugMessage("player >> {}".format(line))
|
||||||
line = line.encode('utf-8')
|
line = line.encode('utf-8')
|
||||||
|
|||||||
@ -1,16 +1,20 @@
|
|||||||
# coding:utf8
|
# coding:utf8x
|
||||||
|
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('.*mpv (\d+)\.(\d+)\.\d+.*')
|
RE_VERSION = re.compile(r'.*mpv (\d+)\.(\d+)\.\d+.*')
|
||||||
osdMessageSeparator = "\\n"
|
osdMessageSeparator = "\\n"
|
||||||
osdMessageSeparator = "; " # TODO: Make conditional
|
osdMessageSeparator = "; " # TODO: Make conditional
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def run(client, playerPath, filePath, args):
|
def run(client, playerPath, filePath, args):
|
||||||
@ -19,9 +23,11 @@ class MpvPlayer(MplayerPlayer):
|
|||||||
except:
|
except:
|
||||||
ver = None
|
ver = None
|
||||||
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("This version of mpv is not known to be compatible with changing the OSC visibility. Please use mpv >=0.28.0.")
|
client.ui.showDebugMessage(
|
||||||
|
"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:
|
||||||
@ -77,6 +83,7 @@ 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'
|
||||||
@ -111,6 +118,7 @@ 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
|
||||||
@ -120,17 +128,18 @@ class NewMpvPlayer(OldMpvPlayer):
|
|||||||
def displayMessage(self, message, duration=(constants.OSD_DURATION * 1000), OSDType=constants.OSD_NOTIFICATION,
|
def displayMessage(self, message, duration=(constants.OSD_DURATION * 1000), OSDType=constants.OSD_NOTIFICATION,
|
||||||
mood=constants.MESSAGE_NEUTRAL):
|
mood=constants.MESSAGE_NEUTRAL):
|
||||||
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("\\\\",constants.MPV_INPUT_BACKSLASH_SUBSTITUTE_CHARACTER).replace("<NEWLINE>", "\\n")
|
messageString = self._sanitizeText(message.replace("\\n", "<NEWLINE>")).replace(
|
||||||
|
"\\\\", 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("\\",constants.MPV_INPUT_BACKSLASH_SUBSTITUTE_CHARACTER))
|
username = self._sanitizeText(username.replace("\\", sconstants.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))
|
||||||
|
|
||||||
@ -141,7 +150,7 @@ class NewMpvPlayer(OldMpvPlayer):
|
|||||||
pauseValue = "yes" if value else "no"
|
pauseValue = "yes" if value else "no"
|
||||||
self._setProperty("pause", pauseValue)
|
self._setProperty("pause", pauseValue)
|
||||||
self._paused = value
|
self._paused = value
|
||||||
if value == False:
|
if not value:
|
||||||
self.lastMPVPositionUpdate = time.time()
|
self.lastMPVPositionUpdate = time.time()
|
||||||
|
|
||||||
def _getProperty(self, property_):
|
def _getProperty(self, property_):
|
||||||
@ -155,25 +164,34 @@ 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 self.fileLoaded == False:
|
if not self.fileLoaded:
|
||||||
self._client.ui.showDebugMessage("File not loaded so using GlobalPosition for getCalculatedPosition({})".format(self._client.getGlobalPosition()))
|
self._client.ui.showDebugMessage(
|
||||||
|
"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("MPV not updated position so using GlobalPosition for getCalculatedPosition ({})".format(self._client.getGlobalPosition()))
|
self._client.ui.showDebugMessage(
|
||||||
|
"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("Recently reset so using self.position for getCalculatedPosition ({})".format(self._position))
|
self._client.ui.showDebugMessage(
|
||||||
|
"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._client.ui.showErrorMessage, getMessage("mpv-unresponsive-error").format(int(diff)), True)
|
self.reactor.callFromThread(
|
||||||
|
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("mpv did not response in time, so assuming position is {} ({}+{})".format(self._position + diff, self._position, diff))
|
self._client.ui.showDebugMessage(
|
||||||
|
"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
|
||||||
@ -184,9 +202,10 @@ class NewMpvPlayer(OldMpvPlayer):
|
|||||||
self._client.ui.showDebugMessage("Recently reset, so storing position as 0")
|
self._client.ui.showDebugMessage("Recently reset, so storing position as 0")
|
||||||
self._position = 0
|
self._position = 0
|
||||||
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("No file loaded so storing position as GlobalPosition ({})".format(self._client.getGlobalPosition()))
|
self._client.ui.showDebugMessage(
|
||||||
|
"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):
|
||||||
@ -205,7 +224,8 @@ 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._paused if self.fileLoaded else self._client.getGlobalPaused(), self.getCalculatedPosition())
|
self._client.updatePlayerStatus(
|
||||||
|
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}")
|
||||||
@ -229,7 +249,8 @@ 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("Did not seek as recently reset and {} below 'do not reset position' threshold".format(value))
|
self._client.ui.showDebugMessage(
|
||||||
|
"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()
|
||||||
@ -245,7 +266,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 resetPosition == False:
|
if not resetPosition:
|
||||||
self.setPosition(self._client.getGlobalPosition())
|
self.setPosition(self._client.getGlobalPosition())
|
||||||
else:
|
else:
|
||||||
self._storePosition(0)
|
self._storePosition(0)
|
||||||
@ -285,7 +306,14 @@ class NewMpvPlayer(OldMpvPlayer):
|
|||||||
self._listener.setReadyToSend(True)
|
self._listener.setReadyToSend(True)
|
||||||
|
|
||||||
def _setOSDPosition(self):
|
def _setOSDPosition(self):
|
||||||
if self._client._config['chatMoveOSD'] and (self._client._config['chatOutputEnabled'] or (self._client._config['chatInputEnabled'] and self._client._config['chatInputPosition'] == constants.INPUT_POSITION_TOP)):
|
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._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']))
|
||||||
|
|
||||||
@ -309,9 +337,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 True if self.fileLoaded else False
|
return bool(self.fileLoaded)
|
||||||
|
|
||||||
if self.fileLoaded == True and self.lastLoadedTime != None and time.time() > (self.lastLoadedTime + constants.MPV_NEWFILE_IGNORE_TIME):
|
return (
|
||||||
return True
|
self.fileLoaded and self.lastLoadedTime is not None and
|
||||||
else:
|
time.time() > (self.lastLoadedTime + constants.MPV_NEWFILE_IGNORE_TIME)
|
||||||
return False
|
)
|
||||||
|
|||||||
@ -1,26 +1,27 @@
|
|||||||
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()
|
||||||
|
|
||||||
def getAvailablePlayerPaths(self):
|
def getAvailablePlayerPaths(self):
|
||||||
l = []
|
l = []
|
||||||
for player in self._players:
|
for player in self._players:
|
||||||
l.extend(player.getDefaultPlayerPathsList())
|
l.extend(player.getDefaultPlayerPathsList())
|
||||||
return l
|
return l
|
||||||
|
|
||||||
def getPlayerByPath(self, path):
|
def getPlayerByPath(self, path):
|
||||||
for player in self._players:
|
for player in self._players:
|
||||||
if player.isValidPlayerPath(path):
|
if player.isValidPlayerPath(path):
|
||||||
return player
|
return player
|
||||||
|
|
||||||
def getPlayerIconByPath(self, path):
|
def getPlayerIconByPath(self, path):
|
||||||
for player in self._players:
|
for player in self._players:
|
||||||
if player.isValidPlayerPath(path):
|
if player.isValidPlayerPath(path):
|
||||||
return player.getIconPath(path)
|
return player.getIconPath(path)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def getExpandedPlayerPathByPath(self, path):
|
def getExpandedPlayerPathByPath(self, path):
|
||||||
for player in self._players:
|
for player in self._players:
|
||||||
if player.isValidPlayerPath(path):
|
if player.isValidPlayerPath(path):
|
||||||
|
|||||||
@ -1,18 +1,24 @@
|
|||||||
import subprocess
|
|
||||||
import re
|
import asynchat
|
||||||
import threading
|
import asyncore
|
||||||
from syncplay.players.basePlayer import BasePlayer
|
|
||||||
from syncplay import constants, utils
|
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
import random
|
import random
|
||||||
|
import re
|
||||||
import socket
|
import socket
|
||||||
import asynchat, asyncore
|
import subprocess
|
||||||
import urllib.request, urllib.parse, urllib.error
|
import sys
|
||||||
|
import threading
|
||||||
import time
|
import time
|
||||||
|
import urllib.error
|
||||||
|
import urllib.parse
|
||||||
|
import urllib.request
|
||||||
|
|
||||||
|
from syncplay import constants, utils
|
||||||
from syncplay.messages import getMessage
|
from syncplay.messages import getMessage
|
||||||
|
from syncplay.players.basePlayer import BasePlayer
|
||||||
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
|
||||||
@ -23,8 +29,8 @@ class VlcPlayer(BasePlayer):
|
|||||||
RE_ANSWER = re.compile(constants.VLC_ANSWER_REGEX)
|
RE_ANSWER = re.compile(constants.VLC_ANSWER_REGEX)
|
||||||
SLAVE_ARGS = constants.VLC_SLAVE_ARGS
|
SLAVE_ARGS = constants.VLC_SLAVE_ARGS
|
||||||
if isMacOS():
|
if isMacOS():
|
||||||
SLAVE_ARGS.extend(constants.VLC_SLAVE_MACOS_ARGS)
|
SLAVE_ARGS.extend(constants.VLC_SLAVE_MACOS_ARGS)
|
||||||
else:
|
else:
|
||||||
SLAVE_ARGS.extend(constants.VLC_SLAVE_NONMACOS_ARGS)
|
SLAVE_ARGS.extend(constants.VLC_SLAVE_NONMACOS_ARGS)
|
||||||
vlcport = random.randrange(constants.VLC_MIN_PORT, constants.VLC_MAX_PORT) if (constants.VLC_MIN_PORT < constants.VLC_MAX_PORT) else constants.VLC_MIN_PORT
|
vlcport = random.randrange(constants.VLC_MIN_PORT, constants.VLC_MAX_PORT) if (constants.VLC_MIN_PORT < constants.VLC_MAX_PORT) else constants.VLC_MIN_PORT
|
||||||
|
|
||||||
@ -42,12 +48,13 @@ class VlcPlayer(BasePlayer):
|
|||||||
self._previousPreviousPosition = -2
|
self._previousPreviousPosition = -2
|
||||||
self._previousPosition = -1
|
self._previousPosition = -1
|
||||||
self._position = 0
|
self._position = 0
|
||||||
try: # Hack to fix locale issue without importing locale library
|
try: # Hack to fix locale issue without importing locale library
|
||||||
self.radixChar = "{:n}".format(1.5)[1:2]
|
self.radixChar = "{:n}".format(1.5)[1:2]
|
||||||
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("Failed to determine locale. As a fallback Syncplay is using the following radix character: \".\".")
|
self._client.ui.showErrorMessage(
|
||||||
|
"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()
|
||||||
@ -110,7 +117,8 @@ 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._position + diff, self._position, diff))
|
self._client.ui.showDebugMessage("VLC did not response in time, so assuming position is {} ({}+{})".format(
|
||||||
|
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)))
|
||||||
@ -119,7 +127,10 @@ class VlcPlayer(BasePlayer):
|
|||||||
else:
|
else:
|
||||||
return self._position
|
return self._position
|
||||||
|
|
||||||
def displayMessage(self, message, duration=constants.OSD_DURATION * 1000, OSDType=constants.OSD_DURATION, mood=constants.MESSAGE_NEUTRAL):
|
def displayMessage(
|
||||||
|
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))
|
||||||
@ -212,21 +223,25 @@ 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 self._filechanged == False) else self._client.getGlobalPaused()
|
self._paused = bool(value != 'playing') if (value != "no-input" and not self._filechanged) 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 self._paused == False \
|
if (
|
||||||
and self._position == self._previousPreviousPosition \
|
not self._paused and
|
||||||
and self._previousPosition == self._position \
|
self._position == self._previousPreviousPosition and
|
||||||
and self._duration > constants.PLAYLIST_LOAD_NEXT_FILE_MINIMUM_LENGTH \
|
self._previousPosition == self._position and
|
||||||
and (self._duration - self._position) < constants.VLC_EOF_DURATION_THRESHOLD \
|
self._duration > constants.PLAYLIST_LOAD_NEXT_FILE_MINIMUM_LENGTH and
|
||||||
and diff > constants.VLC_LATENCY_ERROR_THRESHOLD:
|
(self._duration - self._position) < constants.VLC_EOF_DURATION_THRandD and
|
||||||
|
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 self._filechanged == False) else self._client.getGlobalPosition()
|
newPosition = float(value.replace(",", ".")) if (value != "no-input" and not self._filechanged) else self._client.getGlobalPosition()
|
||||||
if newPosition == self._previousPosition and newPosition != self._duration and not self._paused:
|
if newPosition == self._previousPosition and newPosition != self._duration and not self._paused:
|
||||||
self._client.ui.showDebugMessage("Not considering position {} duplicate as new time because of VLC time precision bug".format(newPosition))
|
self._client.ui.showDebugMessage(
|
||||||
|
"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()
|
||||||
@ -347,7 +362,8 @@ 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(os.getenv('HOME', '.'), "Library/Application Support/org.videolan.vlc/lua/intf/")
|
playerController.vlcIntfUserPath = os.path.join(
|
||||||
|
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.
|
||||||
@ -358,14 +374,17 @@ 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('--lua-config=syncplay={{port=\"{}\"}}'.format(str(playerController.vlcport)))
|
playerController.SLAVE_ARGS.append(
|
||||||
|
'--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('--lua-config=syncplay={{modulepath=\"{}\",port=\"{}\"}}'.format(playerController.vlcModulePath, str(playerController.vlcport)))
|
playerController.SLAVE_ARGS.append(
|
||||||
|
'--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:
|
||||||
@ -376,13 +395,17 @@ class VlcPlayer(BasePlayer):
|
|||||||
self._vlcVersion = None
|
self._vlcVersion = None
|
||||||
|
|
||||||
if self.oldIntfVersion:
|
if self.oldIntfVersion:
|
||||||
self.__playerController.drop(getMessage("vlc-interface-version-mismatch").format(self.oldIntfVersion,constants.VLC_INTERFACE_MIN_VERSION))
|
self.__playerController.drop(
|
||||||
|
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(call, stdin=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE, shell=False, creationflags=0x08000000)
|
self.__process = subprocess.Popen(
|
||||||
|
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()
|
||||||
if self._shouldListenForSTDOUT():
|
if self._shouldListenForSTDOUT():
|
||||||
for line in iter(self.__process.stderr.readline, ''):
|
for line in iter(self.__process.stderr.readline, ''):
|
||||||
@ -405,7 +428,7 @@ class VlcPlayer(BasePlayer):
|
|||||||
if not isMacOS():
|
if not isMacOS():
|
||||||
self.__process.stderr = None
|
self.__process.stderr = None
|
||||||
else:
|
else:
|
||||||
vlcoutputthread = threading.Thread(target = self.handle_vlcoutput, args=())
|
vlcoutputthread = threading.Thread(target=self.handle_vlcoutput, args=())
|
||||||
vlcoutputthread.setDaemon(True)
|
vlcoutputthread.setDaemon(True)
|
||||||
vlcoutputthread.start()
|
vlcoutputthread.start()
|
||||||
threading.Thread.__init__(self, name="VLC Listener")
|
threading.Thread.__init__(self, name="VLC Listener")
|
||||||
@ -416,10 +439,7 @@ class VlcPlayer(BasePlayer):
|
|||||||
self._sendingData = threading.Lock()
|
self._sendingData = threading.Lock()
|
||||||
|
|
||||||
def _shouldListenForSTDOUT(self):
|
def _shouldListenForSTDOUT(self):
|
||||||
if isWindows():
|
return not 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:
|
||||||
@ -461,7 +481,6 @@ class VlcPlayer(BasePlayer):
|
|||||||
self.__playerController.drop()
|
self.__playerController.drop()
|
||||||
break
|
break
|
||||||
out.close()
|
out.close()
|
||||||
|
|
||||||
|
|
||||||
def found_terminator(self):
|
def found_terminator(self):
|
||||||
self.vlcHasResponded = True
|
self.vlcHasResponded = True
|
||||||
|
|||||||
@ -17,4 +17,3 @@ from syncplay.utils import blackholeStdoutForFrozenWindow
|
|||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
blackholeStdoutForFrozenWindow()
|
blackholeStdoutForFrozenWindow()
|
||||||
SyncplayClientManager().run()
|
SyncplayClientManager().run()
|
||||||
|
|
||||||
|
|||||||
@ -19,5 +19,14 @@ from syncplay.server import SyncFactory, ConfigurationGetter
|
|||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
argsGetter = ConfigurationGetter()
|
argsGetter = ConfigurationGetter()
|
||||||
args = argsGetter.getConfiguration()
|
args = argsGetter.getConfiguration()
|
||||||
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))
|
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))
|
||||||
reactor.run()
|
reactor.run()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user