Merge branch 'master' into chat-osd
Conflicts: .appveyor.yml .travis.yml syncplay/constants.py syncplay/messages_de.py syncplay/messages_ru.py syncplay/ui/ConfigurationGetter.py syncplay/ui/gui.py
This commit is contained in:
commit
f3497b3e7e
@ -1,54 +0,0 @@
|
||||
environment:
|
||||
MINICONDA: "C:\\Miniconda"
|
||||
clone_folder: c:\projects\syncplay
|
||||
|
||||
image:
|
||||
- Visual Studio 2013
|
||||
|
||||
platform: x86
|
||||
|
||||
configuration: Release
|
||||
|
||||
init:
|
||||
- set PATH=C:\Miniconda;C:\Miniconda\Scripts;%PATH%
|
||||
- cmd: conda create -n syncplay -y
|
||||
- cmd: activate syncplay
|
||||
- cmd: conda install python pywin32 pyside -y
|
||||
- cmd: pip install twisted py2exe_py2 zope.interface
|
||||
- cmd: type nul > C:\Miniconda\envs\syncplay\lib\site-packages\zope\__init__.py
|
||||
- cmd: pip freeze
|
||||
- cmd: conda list
|
||||
|
||||
install:
|
||||
- cmd: cd c:\projects\syncplay
|
||||
- cmd: python buildPy2exe.py
|
||||
- cmd: del C:\projects\syncplay\syncplay_v1.5.0\lib\DNSAPI.dll
|
||||
- cmd: del C:\projects\syncplay\syncplay_v1.5.0\lib\MPR.dll
|
||||
- cmd: mkdir C:\projects\syncplay\syncplay_v1.5.0\platforms
|
||||
#- cmd: copy C:\Miniconda\envs\syncplay\library\plugins\platforms\qwindows.dll C:\projects\syncplay\syncplay_v1.5.0\platforms\
|
||||
|
||||
# Not a project with an msbuild file, build done at install.
|
||||
build: off
|
||||
|
||||
artifacts:
|
||||
path: 'syncplay_v1.5.0'
|
||||
type: zip
|
||||
name: Syncplay_chat-osd_win
|
||||
|
||||
# Push artefact to S3 bucket and list all
|
||||
before_deploy:
|
||||
- cmd: dir
|
||||
#- cmd: python -c "from PySide2 import QtCore; print QtCore.QLibraryInfo.location(QtCore.QLibraryInfo.PluginsPath)"
|
||||
|
||||
# Deploy build to BinTray
|
||||
deploy:
|
||||
provider: BinTray
|
||||
username: alby128
|
||||
api_key:
|
||||
secure: lAocj5KA9Z9x4BefQBIgNlQJbeW4qPBfCgYVBHMyOP3NgyhnMLmvR57ZCqtCKBlQ
|
||||
subject: Syncplay
|
||||
repo: Syncplay
|
||||
package: Syncplay
|
||||
version: "test"
|
||||
publish: true
|
||||
override: true
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -11,4 +11,3 @@ syncplay_setup.nsi
|
||||
dist.7z
|
||||
.*
|
||||
!.travis.yml
|
||||
!.appveyor.yml
|
||||
|
||||
201
LICENSE
Normal file
201
LICENSE
Normal file
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
16
appdmg.py
16
appdmg.py
@ -27,10 +27,10 @@ compression_level = 9
|
||||
size = defines.get('size', None)
|
||||
|
||||
# Files to include
|
||||
files = [ application, 'resources/lua/intf/syncplay.lua', 'resources/.macos_vlc_install.command' ]
|
||||
files = [ application, 'resources/lua/intf/.syncplay.lua', 'resources/.macos_vlc_install.command', 'resources/.macOS_readme.pdf' ]
|
||||
|
||||
# Symlinks to create
|
||||
symlinks = { 'Applications': '/Applications', 'Install in VLC': '.macos_vlc_install.command' }
|
||||
symlinks = { 'Applications': '/Applications', 'Install for VLC': '.macos_vlc_install.command', 'Read Me': '.macOS_readme.pdf' }
|
||||
|
||||
# Volume icon
|
||||
#
|
||||
@ -43,10 +43,10 @@ badge_icon = icon_from_app(application)
|
||||
|
||||
# Where to put the icons
|
||||
icon_locations = {
|
||||
appname: (80, 80),
|
||||
'Applications': (280, 80),
|
||||
'syncplay.lua': (80, 240),
|
||||
'Install in VLC': (280, 240)
|
||||
appname: (150, 110),
|
||||
'Applications': (450, 110),
|
||||
'Read Me': (100, 285),
|
||||
'Install for VLC': (500, 285)
|
||||
}
|
||||
|
||||
# .. Window configuration ......................................................
|
||||
@ -71,7 +71,7 @@ icon_locations = {
|
||||
#
|
||||
# Other color components may be expressed either in the range 0 to 1, or
|
||||
# as percentages (e.g. 60% is equivalent to 0.6).
|
||||
background = '#bacbe0'
|
||||
background = 'resources/macOS_dmg_bkg.tiff'
|
||||
|
||||
show_status_bar = False
|
||||
show_tab_view = False
|
||||
@ -81,7 +81,7 @@ show_sidebar = False
|
||||
sidebar_width = 180
|
||||
|
||||
# Window position in ((x, y), (w, h)) format
|
||||
window_rect = ((100, 100), (360, 400))
|
||||
window_rect = ((100, 100), (600, 460))
|
||||
|
||||
# Select the default view; must be one of
|
||||
#
|
||||
|
||||
BIN
resources/macOS_dmg_bkg.tiff
Normal file
BIN
resources/macOS_dmg_bkg.tiff
Normal file
Binary file not shown.
BIN
resources/macOS_readme.pdf
Normal file
BIN
resources/macOS_readme.pdf
Normal file
Binary file not shown.
@ -2,4 +2,4 @@
|
||||
|
||||
mkdir -p $HOME/Library/Application\ Support/org.videolan.vlc/lua/intf/
|
||||
|
||||
cp /Volumes/Syncplay/syncplay.lua $HOME/Library/Application\ Support/org.videolan.vlc/lua/intf/
|
||||
cp /Volumes/Syncplay/.syncplay.lua $HOME/Library/Application\ Support/org.videolan.vlc/lua/intf/syncplay.lua
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
version = '1.5.0'
|
||||
milestone = 'Yoitsu'
|
||||
release_number = '40'
|
||||
release_number = '45'
|
||||
projectURL = 'http://syncplay.pl/'
|
||||
|
||||
@ -92,6 +92,8 @@ class SyncplayClient(object):
|
||||
if config['password']:
|
||||
config['password'] = hashlib.md5(config['password']).hexdigest()
|
||||
self._serverPassword = config['password']
|
||||
self._host = u"{}:{}".format(config['host'],config['port'])
|
||||
self._publicServers = config["publicServers"]
|
||||
if not config['file']:
|
||||
self.__getUserlistOnLogon = True
|
||||
else:
|
||||
@ -648,7 +650,20 @@ class SyncplayClient(object):
|
||||
self.userlist.showUserList(altUI)
|
||||
|
||||
def getPassword(self):
|
||||
return self._serverPassword
|
||||
if self.thisIsPublicServer():
|
||||
return ""
|
||||
else:
|
||||
return self._serverPassword
|
||||
|
||||
def thisIsPublicServer(self):
|
||||
self._publicServers = []
|
||||
if self._publicServers and self._host in self._publicServers:
|
||||
return True
|
||||
i = 0
|
||||
for server in constants.FALLBACK_PUBLIC_SYNCPLAY_SERVERS:
|
||||
if server[1] == self._host:
|
||||
return True
|
||||
i += 1
|
||||
|
||||
def setPosition(self, position):
|
||||
if self._lastPlayerUpdate:
|
||||
@ -1620,11 +1635,23 @@ class SyncplayPlaylist():
|
||||
self.changePlaylist(newPlaylist, username=None)
|
||||
|
||||
@needsSharedPlaylistsEnabled
|
||||
def shufflePlaylist(self):
|
||||
def shuffleRemainingPlaylist(self):
|
||||
if self._playlist and len(self._playlist) > 0:
|
||||
shuffledPlaylist = deepcopy(self._playlist)
|
||||
shufflePoint = self._playlistIndex + 1
|
||||
partToKeep = shuffledPlaylist[:shufflePoint]
|
||||
partToShuffle = shuffledPlaylist[shufflePoint:]
|
||||
random.shuffle(partToShuffle)
|
||||
shuffledPlaylist = partToKeep + partToShuffle
|
||||
self.changePlaylist(shuffledPlaylist, username=None, resetIndex=False)
|
||||
|
||||
@needsSharedPlaylistsEnabled
|
||||
def shuffleEntirePlaylist(self):
|
||||
if self._playlist and len(self._playlist) > 0:
|
||||
shuffledPlaylist = deepcopy(self._playlist)
|
||||
random.shuffle(shuffledPlaylist)
|
||||
self.changePlaylist(shuffledPlaylist, username=None, resetIndex=True)
|
||||
self.switchToNewPlaylistIndex(0, resetPosition=True)
|
||||
|
||||
def canUndoPlaylist(self, currentPlaylist):
|
||||
return self._previousPlaylist is not None and currentPlaylist <> self._previousPlaylist
|
||||
|
||||
@ -55,6 +55,7 @@ SYNC_ON_PAUSE = True # Client seek to global position - subtitles may disappear
|
||||
PLAYLIST_MAX_CHARACTERS = 10000
|
||||
PLAYLIST_MAX_ITEMS = 250
|
||||
MAXIMUM_TAB_WIDTH = 350
|
||||
TAB_PADDING = 30
|
||||
DEFAULT_WINDOWS_MONOSPACE_FONT = "Consolas"
|
||||
DEFAULT_OSX_MONOSPACE_FONT = "Menlo"
|
||||
FALLBACK_MONOSPACE_FONT = "Monospace"
|
||||
@ -186,6 +187,7 @@ MPV_SYNCPLAYINTF_CONSTANTS_TO_SEND = ["MaxChatMessageLength={}".format(MAX_CHAT_
|
||||
MPV_SYNCPLAYINTF_LANGUAGE_TO_SEND = ["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',
|
||||
'--play-and-pause', '--start-time=0']
|
||||
VLC_SLAVE_OSX_ARGS = ['--verbose=2', '--no-file-logging']
|
||||
VLC_SLAVE_NONOSX_ARGS = ['--no-one-instance', '--no-one-instance-when-started-from-file']
|
||||
MPV_SUPERSEDE_IF_DUPLICATE_COMMANDS = ["no-osd set time-pos ", "loadfile "]
|
||||
MPV_REMOVE_BOTH_IF_DUPLICATE_COMMANDS = ["cycle pause"]
|
||||
@ -208,6 +210,8 @@ INPUT_POSITION_TOP = "Top"
|
||||
INPUT_POSITION_MIDDLE = "Middle"
|
||||
INPUT_POSITION_BOTTOM = "Bottom"
|
||||
|
||||
VLC_EOF_DURATION_THRESHOLD = 2.0
|
||||
|
||||
PRIVACY_HIDDENFILENAME = "**Hidden filename**"
|
||||
INVERTED_STATE_MARKER = "*"
|
||||
ERROR_MESSAGE_MARKER = "*"
|
||||
|
||||
@ -93,6 +93,7 @@ de = {
|
||||
"language-changed-msgbox-label" : u"Die Sprache wird geändert, wenn du Syncplay neu startest.",
|
||||
"promptforupdate-label" : u"Soll Syncplay regelmäßig nach Updates suchen?",
|
||||
|
||||
"vlc-version-mismatch": u"This version of VLC does not support Syncplay. VLC {}+ supports Syncplay but VLC 3 does not. Please use an alternative media player.", # VLC min version # TODO: Translate
|
||||
"vlc-interface-version-mismatch": u"Du nutzt Version {} des VLC-Syncplay Interface-Moduls, Syncplay benötigt aber mindestens Version {}. In der Syncplay-Anleitung unter http://syncplay.pl/guide/ [Englisch] findest du Details zur Installation des syncplay.lua-Skripts.", # VLC interface version, VLC interface min version
|
||||
"vlc-interface-oldversion-warning": u"Warnung: Es ist eine alte Version des Syncplay Interface-Moduls für VLC im VLC-Verzeichnis installiert. In der Syncplay-Anleitung unter http://syncplay.pl/guide/ [Englisch] findest du Details zur Installation des syncplay.lua-Skripts.",
|
||||
"vlc-interface-not-installed": u"Warnung: Es wurde kein Syncplay Interface-Modul für VLC im VLC-Verzeichnis gefunden. Daher wird, wenn du VLC 2.0 nutzt, die syncplay.lua die mit Syncplay mitgeliefert wurde, verwendet. Dies bedeutet allerdings, dass keine anderen Interface-Skripts und Erweiterungen geladen werden. In der Syncplay-Anleitung unter http://syncplay.pl/guide/ [Englisch] findest du Details zur Installation des syncplay.lua-Skripts.",
|
||||
@ -131,14 +132,9 @@ de = {
|
||||
"vlc-failed-connection": u"Kann nicht zu VLC verbinden. Wenn du syncplay.lua nicht installiert hast, findest du auf http://syncplay.pl/LUA/ [Englisch] eine Anleitung.",
|
||||
"vlc-failed-noscript": u"Laut VLC ist das syncplay.lua Interface-Skript nicht installiert. Auf http://syncplay.pl/LUA/ [Englisch] findest du eine Anleitung.",
|
||||
"vlc-failed-versioncheck": u"Diese VLC-Version wird von Syncplay nicht unterstützt. Bitte nutze VLC 2.0",
|
||||
"vlc-failed-other" : u"Beim Laden des syncplay.lua Interface-Skripts durch VLC trat folgender Fehler auf: {}", # Syncplay Error
|
||||
|
||||
"feature-sharedPlaylists": u"shared playlists", # used for not-supported-by-server-error # TODO: Translate
|
||||
"feature-chat": u"chat", # used for not-supported-by-server-error # TODO: Translate
|
||||
"feature-readiness": u"readiness", # used for not-supported-by-server-error # TODO: Translate
|
||||
"feature-managedRooms": u"managed rooms", # used for not-supported-by-server-error # TODO: Translate
|
||||
|
||||
"not-supported-by-server-error": u"The {} feature is not supported by this server..", # feature # TODO: Translate
|
||||
#OLD TRANSLATION: "not-supported-by-server-error" : u"Dieses Feature wird vom Server nicht unterstützt. Es wird ein Server mit Syncplay Version {}+ benötigt, aktuell verwendet wird jedoch Version {}.", #minVersion, serverVersion
|
||||
"not-supported-by-server-error" : u"Dieses Feature wird vom Server nicht unterstützt. Es wird ein Server mit Syncplay Version {}+ benötigt, aktuell verwendet wird jedoch Version {}.", #minVersion, serverVersion
|
||||
"shared-playlists-not-supported-by-server-error" : "The shared playlists feature may not be supported by the server. To ensure that it works correctly requires a server running Syncplay {}+, but the server is running Syncplay {}.", #minVersion, serverVersion # TODO: Translate
|
||||
"shared-playlists-disabled-by-server-error" : "The shared playlist feature has been disabled in the server configuration. To use this feature you will need to connect to a different server.", # TODO: Translate
|
||||
|
||||
@ -185,7 +181,7 @@ de = {
|
||||
|
||||
"media-setting-title" : u"Media-Player Einstellungen",
|
||||
"executable-path-label" : u"Pfad zum Media-Player:",
|
||||
"media-path-label" : u"Pfad zur Datei:",
|
||||
"media-path-label" : u"Pfad zur Datei:", # Todo: Translate to 'Path to video (optional)'
|
||||
"player-arguments-label" : u"Playerparameter:",
|
||||
"browse-label" : u"Durchsuchen",
|
||||
"update-server-list-label" : u"Liste aktualisieren",
|
||||
@ -262,7 +258,7 @@ de = {
|
||||
"run-label" : u"Syncplay starten",
|
||||
"storeandrun-label" : u"Konfiguration speichern und Syncplay starten",
|
||||
|
||||
"contact-label" : u"Du hast eine Idee, einen Bug gefunden oder möchtest Feedback geben? Sende eine E-Mail an <a href=\"mailto:dev@syncplay.pl\">dev@syncplay.pl</a>, chatte auf dem <a href=\"https://webchat.freenode.net/?channels=#syncplay\">#Syncplay IRC-Kanal</a> auf irc.freenode.net oder <a href=\"https://github.com/Uriziel/syncplay/issues\">öffne eine Fehlermeldung auf GitHub</a>. Außerdem findest du auf <a href=\"http://syncplay.pl/\">http://syncplay.pl/</a> weitere Informationen, Hilfestellungen und Updates. NOTE: Chat messages are not encrypted so do not use Syncplay to send sensitive information.", # TODO: Translate message at end
|
||||
"contact-label" : u"Du hast eine Idee, einen Bug gefunden oder möchtest Feedback geben? Sende eine E-Mail an <a href=\"mailto:dev@syncplay.pl\">dev@syncplay.pl</a>, chatte auf dem <a href=\"https://webchat.freenode.net/?channels=#syncplay\">#Syncplay IRC-Kanal</a> auf irc.freenode.net oder <a href=\"https://github.com/Uriziel/syncplay/issues\">öffne eine Fehlermeldung auf GitHub</a>. Außerdem findest du auf <a href=\"http://syncplay.pl/\">http://syncplay.pl/</a> weitere Informationen, Hilfestellungen und Updates. OTE: Chat messages are not encrypted so do not use Syncplay to send sensitive information.", # TODO: Translate last sentence
|
||||
|
||||
"joinroom-label" : u"Raum beitreten",
|
||||
"joinroom-menu-label" : u"Raum beitreten {}", #TODO: Might want to fix this
|
||||
@ -345,7 +341,7 @@ de = {
|
||||
"room-tooltip" : u"Der Raum, der betreten werden soll, kann ein x-beliebiger sein. Allerdings werden nur Clients im selben Raum synchronisiert.",
|
||||
|
||||
"executable-path-tooltip" : u"Pfad zum ausgewählten, unterstützten Mediaplayer (MPC-HC, VLC, mplayer2 or mpv).",
|
||||
"media-path-tooltip" : u"Pfad zum wiederzugebenden Video oder Stream. Notwendig für mpv und mplayer2.",
|
||||
"media-path-tooltip" : u"Pfad zum wiederzugebenden Video oder Stream. Notwendig für mplayer2.", # TODO: Confirm translation
|
||||
"player-arguments-tooltip" : u"Zusätzliche Kommandozeilenparameter / -schalter für diesen Mediaplayer.",
|
||||
"mediasearcdirectories-arguments-tooltip" : u"Verzeichnisse, in denen Syncplay nach Mediendateien suchen soll, z.B. wenn du das Click-to-switch-Feature verwendest. Syncplay wird rekursiv Unterordner durchsuchen.", # TODO: Translate Click-to-switch? (or use as name for feature)
|
||||
|
||||
@ -451,7 +447,8 @@ de = {
|
||||
"cannot-add-unsafe-path-error" : u"Could not automatically load {} because it is not on a trusted domain. You can switch to the URL manually by double clicking it in the playlist, and add trusted domains via File->Advanced->Set Trusted Domains. If you right click on a URL then you can add its domain as a trusted domain via the context menu.", # Filename
|
||||
"sharedplaylistenabled-label" : u"Enable shared playlists",
|
||||
"removefromplaylist-menu-label" : u"Remove from playlist",
|
||||
"shuffleplaylist-menuu-label" : u"Shuffle playlist",
|
||||
"shuffleremainingplaylist-menu-label" : u"Shuffle remaining playlist",
|
||||
"shuffleentireplaylist-menuu-label" : u"Shuffle entire playlist",
|
||||
"undoplaylist-menu-label" : u"Undo last change to playlist",
|
||||
"addfilestoplaylist-menu-label" : u"Add file(s) to bottom of playlist",
|
||||
"addurlstoplaylist-menu-label" : u"Add URL(s) to bottom of playlist",
|
||||
|
||||
@ -109,7 +109,7 @@ en = {
|
||||
"mpc-version-insufficient-error" : "MPC version not sufficient, please use `mpc-hc` >= `{}`",
|
||||
"mpv-version-error" : "Syncplay is not compatible with this version of mpv. Please use a different version of mpv (e.g. Git HEAD).",
|
||||
"player-file-open-error" : "Player failed opening file",
|
||||
"player-path-error" : "Player path is not set properly",
|
||||
"player-path-error" : "Player path is not set properly. Supported players are: mpv, VLC, MPC-HC and mplayer2",
|
||||
"hostname-empty-error" : "Hostname can't be empty",
|
||||
"empty-error" : "{} can't be empty", # Configuration
|
||||
"media-player-error": "Media player error: \"{}\"", # Error line
|
||||
@ -119,7 +119,7 @@ en = {
|
||||
|
||||
"unable-to-start-client-error" : "Unable to start client",
|
||||
|
||||
"player-path-config-error": "Player path is not set properly",
|
||||
"player-path-config-error": "Player path is not set properly. Supported players are: mpv, VLC, MPC-HC and mplayer2.",
|
||||
"no-file-path-config-error" :"File must be selected before starting your player",
|
||||
"no-hostname-config-error": "Hostname can't be empty",
|
||||
"invalid-port-config-error" : "Port must be valid",
|
||||
@ -184,7 +184,7 @@ en = {
|
||||
|
||||
"media-setting-title" : "Media player settings",
|
||||
"executable-path-label" : "Path to media player:",
|
||||
"media-path-label" : "Path to media file:",
|
||||
"media-path-label" : "Path to video (optional):",
|
||||
"player-arguments-label" : "Player arguments (if any):",
|
||||
"browse-label" : "Browse",
|
||||
"update-server-list-label" : u"Update list",
|
||||
@ -345,8 +345,8 @@ en = {
|
||||
"password-tooltip" : "Passwords are only needed for connecting to private servers.",
|
||||
"room-tooltip" : "Room to join upon connection can be almost anything, but you will only be synchronised with people in the same room.",
|
||||
|
||||
"executable-path-tooltip" : "Location of your chosen supported media player (MPC-HC, VLC, mplayer2 or mpv).",
|
||||
"media-path-tooltip" : "Location of video or stream to be opened. Necessary for mpv and mplayer2.",
|
||||
"executable-path-tooltip" : "Location of your chosen supported media player (mpv, VLC, MPC-HC or mplayer2).",
|
||||
"media-path-tooltip" : "Location of video or stream to be opened. Necessary for mplayer2.",
|
||||
"player-arguments-tooltip" : "Additional command line arguments / switches to pass on to this media player.",
|
||||
"mediasearcdirectories-arguments-tooltip" : u"Directories where Syncplay will search for media files, e.g. when you are using the click to switch feature. Syncplay will look recursively through sub-folders.",
|
||||
|
||||
@ -451,7 +451,8 @@ en = {
|
||||
"cannot-add-unsafe-path-error" : u"Could not automatically load {} because it is not on a trusted domain. You can switch to the URL manually by double clicking it in the playlist, and add trusted domains via File->Advanced->Set Trusted Domains. If you right click on a URL then you can add its domain as a trusted domain via the context menu.", # Filename
|
||||
"sharedplaylistenabled-label" : u"Enable shared playlists",
|
||||
"removefromplaylist-menu-label" : u"Remove from playlist",
|
||||
"shuffleplaylist-menuu-label" : u"Shuffle playlist",
|
||||
"shuffleremainingplaylist-menu-label" : u"Shuffle remaining playlist",
|
||||
"shuffleentireplaylist-menuu-label" : u"Shuffle entire playlist",
|
||||
"undoplaylist-menu-label" : u"Undo last change to playlist",
|
||||
"addfilestoplaylist-menu-label" : u"Add file(s) to bottom of playlist",
|
||||
"addurlstoplaylist-menu-label" : u"Add URL(s) to bottom of playlist",
|
||||
|
||||
@ -93,6 +93,7 @@ ru = {
|
||||
"language-changed-msgbox-label" : u"Язык переключится при следующем запуске Syncplay.",
|
||||
"promptforupdate-label" : u"Вы не против, если Syncplay будет автоматически изредка проверять наличие обновлений?",
|
||||
|
||||
"vlc-version-mismatch": u"Syncplay не поддерживает данную версию VLC. Syncplay поддерживает VLC {}+, но не VLC 3. Используйте другой проигрыватель.", # VLC min version
|
||||
"vlc-interface-version-mismatch" : u"Вы используете модуль интерфейса Syncplay устаревшей версии {} для VLC. К сожалению, Syncplay способен работать с версией {} и выше. Пожалуйста, обратитесь к Руководству Пользователя Syncplay (http://syncplay.pl/guide/) за инструкциями о том, как установить syncplay.lua.", # VLC interface version, VLC interface min version
|
||||
"vlc-interface-oldversion-warning" : u"Внимание: Syncplay обнаружил, что старая версия модуля интерфейса Syncplay для VLC уже установлена в директорию VLC. Пожалуйста, обратитесь к Руководству Пользователя Syncplay (http://syncplay.pl/guide/) за инструкциями о том, как установить syncplay.lua.",
|
||||
"vlc-interface-not-installed" : u"Внимание: Модуль интерфейса Syncplay для VLC не обнаружен в директории VLC. По существу, если Вы используете VLC 2.0, то VLC будет использовать модуль syncplay.lua из директории Syncplay, но в таком случае другие пользовательские скрипты и расширения интерфейса не будут работать. Пожалуйста, обратитесь к Руководству Пользователя Syncplay (http://syncplay.pl/guide/) за инструкциями о том, как установить syncplay.lua.",
|
||||
@ -109,7 +110,7 @@ ru = {
|
||||
"mpc-version-insufficient-error" : u"Версия MPC слишком старая, пожалуйста, используйте `mpc-hc` >= `{}`",
|
||||
"mpv-version-error" : u"Syncplay не совместим с данной версией mpv. Пожалуйста, используйте другую версию mpv (лучше свежайшую).",
|
||||
"player-file-open-error" : u"Проигрыватель не может открыть файл.",
|
||||
"player-path-error" : u"Путь к проигрывателю задан неверно.",
|
||||
"player-path-error" : u"Путь к проигрывателю задан неверно. Supported players are: mpv, VLC, MPC-HC and mplayer2.", # TODO: Translate last sentence
|
||||
"hostname-empty-error" : u"Имя пользователя не может быть пустым.",
|
||||
"empty-error" : u"{} не может быть пустым.", # Configuration
|
||||
"media-player-error" : u"Ошибка проигрывателя: \"{}\"", # Error line
|
||||
@ -119,7 +120,7 @@ ru = {
|
||||
|
||||
"unable-to-start-client-error" : u"Невозможно запустить клиент",
|
||||
|
||||
"player-path-config-error": u"Путь к проигрывателю установлен неверно",
|
||||
"player-path-config-error": u"Путь к проигрывателю установлен неверно. Supported players are: mpv, VLC, MPC-HC and mplayer2", # To do: Translate end
|
||||
"no-file-path-config-error" : u"Файл должен быть указан до включения проигрывателя",
|
||||
"no-hostname-config-error": u"Имя сервера не может быть пустым",
|
||||
"invalid-port-config-error" : u"Неверный номер порта",
|
||||
@ -131,6 +132,7 @@ ru = {
|
||||
"vlc-failed-connection" : u"Ошибка подключения к VLC. Если у Вас не установлен syncplay.lua, то обратитесь к http://syncplay.pl/LUA/ за инструкциями.",
|
||||
"vlc-failed-noscript" : u"VLC сообщает, что скрипт интерфейса syncplay.lua не установлен. Пожалуйста, обратитесь к http://syncplay.pl/LUA/ за инструкциями.",
|
||||
"vlc-failed-versioncheck" : u"Данная версия VLC не поддерживается Syncplay. Пожалуйста, используйте VLC версии 2 или выше.",
|
||||
"vlc-failed-other" : u"Во время загрузки скрипта интерфейса syncplay.lua в VLC произошла следующая ошибка: {}", # Syncplay Error
|
||||
|
||||
"feature-sharedPlaylists": u"shared playlists", # used for not-supported-by-server-error # TODO: Translate
|
||||
"feature-chat": u"chat", # used for not-supported-by-server-error # TODO: Translate
|
||||
@ -185,7 +187,7 @@ ru = {
|
||||
|
||||
"media-setting-title" : u"Воспроизведение",
|
||||
"executable-path-label" : u"Путь к проигрывателю:",
|
||||
"media-path-label" : u"Путь к видеофайлу:",
|
||||
"media-path-label" : u"Путь к видеофайлу:", # Todo: Translate to 'Path to video (optional)'
|
||||
"player-arguments-label" : u"Аргументы запуска проигрывателя:",
|
||||
"browse-label" : u"Выбрать",
|
||||
"update-server-list-label" : u"Обновить список",
|
||||
@ -265,7 +267,7 @@ ru = {
|
||||
"run-label" : u"Запустить",
|
||||
"storeandrun-label" : u"Сохранить и запустить",
|
||||
|
||||
"contact-label" : u"Есть идея, нашли ошибку или хотите оставить отзыв? Пишите на <a href=\"mailto:dev@syncplay.pl\">dev@syncplay.pl</a>, в <a href=\"https://webchat.freenode.net/?channels=#syncplay\">IRC канал #Syncplay</a> на irc.freenode.net или <a href=\"https://github.com/Uriziel/syncplay/issues\">задавайте вопросы через GitHub</a>. Кроме того, заходите на <a href=\"http://syncplay.pl/\">www.syncplay.pl</a> за инорфмацией, помощью и обновлениями! NOTE: Chat messages are not encrypted so do not use Syncplay to send sensitive information.", # TODO: Translate end of message
|
||||
"contact-label" : u"Есть идея, нашли ошибку или хотите оставить отзыв? Пишите на <a href=\"mailto:dev@syncplay.pl\">dev@syncplay.pl</a>, в <a href=\"https://webchat.freenode.net/?channels=#syncplay\">IRC канал #Syncplay</a> на irc.freenode.net или <a href=\"https://github.com/Uriziel/syncplay/issues\">задавайте вопросы через GitHub</a>. Кроме того, заходите на <a href=\"http://syncplay.pl/\">www.syncplay.pl</a> за инорфмацией, помощью и обновлениями! NOTE: Chat messages are not encrypted so do not use Syncplay to send sensitive information.", # TODO: Translate last sentence
|
||||
|
||||
"joinroom-label" : u"Зайти в комнату",
|
||||
"joinroom-menu-label" : u"Зайти в комнату {}",
|
||||
@ -347,7 +349,7 @@ ru = {
|
||||
"room-tooltip" : u"Комната, в которую Вы попадете сразу после подключения. Синхронизация возможна только между людьми в одной и той же комнате.",
|
||||
|
||||
"executable-path-tooltip" : u"Расположение Вашего видеопроигрывателя (MPC-HC, VLC, mplayer2 или mpv).",
|
||||
"media-path-tooltip" : u"Расположение видеофайла или потока для просмотра. Обязательно для mpv и mplayer2.",
|
||||
"media-path-tooltip" : u"Расположение видеофайла или потока для просмотра. Обязательно для mplayer2.", # TODO: Confirm translation
|
||||
"player-arguments-tooltip" : u"Передавать дополнительные аргументы командной строки этому проигрывателю.",
|
||||
"mediasearcdirectories-arguments-tooltip" : u"Папки, где Syncplay будет искать медиа файлы, включая подпапки.",
|
||||
|
||||
@ -450,7 +452,8 @@ ru = {
|
||||
"cannot-add-unsafe-path-error" : u"Не удалось автоматически переключиться на {}, потому что ссылка не соответствует доверенным сайтам. Её можно включить вручную, дважны кливнув по ссылке в списке воспроизведения. Добавить доверенный сайт можно в выпадающем меню 'Дополнительно' или просто кликнув по ссылке правой кнопкой мыши.", # Filename
|
||||
"sharedplaylistenabled-label" : u"Включить общий список воспроизведения",
|
||||
"removefromplaylist-menu-label" : u"Удалить",
|
||||
"shuffleplaylist-menuu-label" : u"Перемешать список",
|
||||
"shufflepremaininglaylist-menuu-label" : u"Shuffle remaining playlist", # Was: Перемешать список # TODO: Translate
|
||||
"shuffleentireplaylist-menuu-label" : u"Shuffle entire playlist", # TODO: Translate
|
||||
"undoplaylist-menu-label" : u"Отменить последнее действие",
|
||||
"addfilestoplaylist-menu-label" : u"Добавить файлы в очередь",
|
||||
"addurlstoplaylist-menu-label" : u"Добавить ссылку в очередь",
|
||||
|
||||
@ -395,7 +395,12 @@ class MplayerPlayer(BasePlayer):
|
||||
for itemID, deletionCandidate in enumerate(self.sendQueue):
|
||||
if deletionCandidate.startswith(command):
|
||||
self.__playerController._client.ui.showDebugMessage(u"<mpv> Remove duplicate (supersede): {}".format(self.sendQueue[itemID]))
|
||||
self.sendQueue.remove(self.sendQueue[itemID])
|
||||
try:
|
||||
self.sendQueue.remove(self.sendQueue[itemID])
|
||||
except UnicodeWarning:
|
||||
self.__playerController._client.ui.showDebugMessage(u"<mpv> Unicode mismatch occured when trying to remove duplicate")
|
||||
# TODO: Prevent this from being triggered
|
||||
pass
|
||||
break
|
||||
break
|
||||
if constants.MPV_REMOVE_BOTH_IF_DUPLICATE_COMMANDS:
|
||||
|
||||
30
syncplay/players/vlc.py
Normal file → Executable file
30
syncplay/players/vlc.py
Normal file → Executable file
@ -21,8 +21,10 @@ class VlcPlayer(BasePlayer):
|
||||
|
||||
RE_ANSWER = re.compile(constants.VLC_ANSWER_REGEX)
|
||||
SLAVE_ARGS = constants.VLC_SLAVE_ARGS
|
||||
if not sys.platform.startswith('darwin'):
|
||||
SLAVE_ARGS.extend(constants.VLC_SLAVE_NONOSX_ARGS)
|
||||
if sys.platform.startswith('darwin'):
|
||||
SLAVE_ARGS.extend(constants.VLC_SLAVE_OSX_ARGS)
|
||||
else:
|
||||
SLAVE_ARGS.extend(constants.VLC_SLAVE_NONOSX_ARGS)
|
||||
vlcport = random.randrange(constants.VLC_MIN_PORT, constants.VLC_MAX_PORT) if (constants.VLC_MIN_PORT < constants.VLC_MAX_PORT) else constants.VLC_MIN_PORT
|
||||
|
||||
def __init__(self, client, playerPath, filePath, args):
|
||||
@ -207,18 +209,22 @@ class VlcPlayer(BasePlayer):
|
||||
self._durationAsk.set()
|
||||
elif name == "playstate":
|
||||
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
|
||||
if self._paused == False \
|
||||
and self._position == self._previousPreviousPosition \
|
||||
and self._previousPosition == self._position \
|
||||
and self._duration > constants.PLAYLIST_LOAD_NEXT_FILE_MINIMUM_LENGTH \
|
||||
and self._position == self._duration:
|
||||
self._paused = True
|
||||
and (self._duration - self._position) < constants.VLC_EOF_DURATION_THRESHOLD \
|
||||
and diff > constants.VLC_LATENCY_ERROR_THRESHOLD:
|
||||
self._client.ui.showDebugMessage("Treating 'playing' response as 'paused' due to VLC EOF bug")
|
||||
self.setPaused(True)
|
||||
self._pausedAsk.set()
|
||||
elif name == "position":
|
||||
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 not self._paused:
|
||||
self._client.ui.showDebugMessage("Not considering position {} duplicate as new time because of VLC time precision bug".format(newPosition))
|
||||
self._previousPreviousPosition = self._previousPosition
|
||||
self._previousPosition = self._position
|
||||
self._positionAsk.set()
|
||||
return
|
||||
self._previousPreviousPosition = self._previousPosition
|
||||
@ -382,7 +388,12 @@ class VlcPlayer(BasePlayer):
|
||||
playerController._client.ui.showErrorMessage(
|
||||
getMessage("media-player-error").format(line), True)
|
||||
break
|
||||
self.__process.stderr = None
|
||||
if not sys.platform.startswith('darwin'):
|
||||
self.__process.stderr = None
|
||||
else:
|
||||
vlcoutputthread = threading.Thread(target = self.handle_vlcoutput, args=())
|
||||
vlcoutputthread.setDaemon(True)
|
||||
vlcoutputthread.start()
|
||||
threading.Thread.__init__(self, name="VLC Listener")
|
||||
asynchat.async_chat.__init__(self)
|
||||
self.set_terminator("\n")
|
||||
@ -428,6 +439,15 @@ class VlcPlayer(BasePlayer):
|
||||
asynchat.async_chat.handle_close(self)
|
||||
self.__playerController.drop(getMessage("vlc-failed-connection").format(constants.VLC_MIN_VERSION))
|
||||
|
||||
def handle_vlcoutput(self):
|
||||
out = self.__process.stderr
|
||||
for line in iter(out.readline, ''):
|
||||
if '[syncplay] core interface debug: removing module' in line:
|
||||
self.__playerController.drop()
|
||||
break
|
||||
out.close()
|
||||
|
||||
|
||||
def found_terminator(self):
|
||||
self.vlcHasResponded = True
|
||||
self.__playerController.lineReceived("".join(self._ibuffer))
|
||||
|
||||
@ -348,13 +348,19 @@ class SyncServerProtocol(JSONCommandProtocol):
|
||||
|
||||
def _extractHelloArguments(self, hello):
|
||||
roomName = None
|
||||
username = hello["username"] if hello.has_key("username") else None
|
||||
username = username.strip()
|
||||
if hello.has_key("username"):
|
||||
username = hello["username"]
|
||||
username = username.strip()
|
||||
else:
|
||||
username = None
|
||||
serverPassword = hello["password"] if hello.has_key("password") else None
|
||||
room = hello["room"] if hello.has_key("room") else None
|
||||
if room:
|
||||
roomName = room["name"] if room.has_key("name") else None
|
||||
roomName = roomName.strip()
|
||||
if room.has_key("name"):
|
||||
roomName = room["name"]
|
||||
roomName = roomName.strip()
|
||||
else:
|
||||
roomName = None
|
||||
version = hello["version"] if hello.has_key("version") else None
|
||||
version = hello["realversion"] if hello.has_key("realversion") else version
|
||||
features = hello["features"] if hello.has_key("features") else None
|
||||
|
||||
@ -397,7 +397,6 @@ class Watcher(object):
|
||||
reactor.callLater(0.1, self._scheduleSendState)
|
||||
|
||||
def setFile(self, file_):
|
||||
print file_
|
||||
if file_ and file_.has_key("name"):
|
||||
file_["name"] = truncateText(file_["name"],constants.MAX_FILENAME_LENGTH)
|
||||
self._file = file_
|
||||
|
||||
@ -85,6 +85,7 @@ class ConfigurationGetter(object):
|
||||
"notificationTimeout": 3,
|
||||
"alertTimeout": 5,
|
||||
"chatTimeout": 7,
|
||||
"publicServers" : []
|
||||
}
|
||||
|
||||
self._defaultConfig = self._config.copy()
|
||||
@ -142,6 +143,7 @@ class ConfigurationGetter(object):
|
||||
"perPlayerArguments",
|
||||
"mediaSearchDirectories",
|
||||
"trustedDomains",
|
||||
"publicServers",
|
||||
]
|
||||
|
||||
self._numeric = [
|
||||
@ -179,7 +181,7 @@ class ConfigurationGetter(object):
|
||||
"autoplayInitialState", "mediaSearchDirectories",
|
||||
"sharedPlaylistEnabled", "loopAtEndOfPlaylist",
|
||||
"loopSingleFiles",
|
||||
"onlySwitchToTrustedDomains", "trustedDomains"],
|
||||
"onlySwitchToTrustedDomains", "trustedDomains","publicServers"],
|
||||
"gui": ["showOSD", "showOSDWarnings", "showSlowdownOSD",
|
||||
"showDifferentRoomOSD", "showSameRoomOSD",
|
||||
"showNonControllerOSD", "showDurationNotification",
|
||||
|
||||
@ -89,6 +89,9 @@ class ConfigDialog(QtGui.QDialog):
|
||||
self.resetButton.show()
|
||||
self.playerargsTextbox.show()
|
||||
self.playerargsLabel.show()
|
||||
self.mediapathTextbox.show()
|
||||
self.mediapathLabel.show()
|
||||
self.mediabrowseButton.show()
|
||||
self.runButton.show()
|
||||
self.saveMoreState(True)
|
||||
self.tabListWidget.setCurrentRow(0)
|
||||
@ -100,6 +103,14 @@ class ConfigDialog(QtGui.QDialog):
|
||||
self.playerargsTextbox.hide()
|
||||
self.playerargsLabel.hide()
|
||||
self.runButton.hide()
|
||||
if self.mediapathTextbox.text() == "":
|
||||
self.mediapathTextbox.hide()
|
||||
self.mediapathLabel.hide()
|
||||
self.mediabrowseButton.hide()
|
||||
else:
|
||||
self.mediapathTextbox.show()
|
||||
self.mediapathLabel.show()
|
||||
self.mediabrowseButton.show()
|
||||
self.saveMoreState(False)
|
||||
self.stackedLayout.setCurrentIndex(0)
|
||||
newHeight = self.connectionSettingsGroup.minimumSizeHint().height()+self.mediaplayerSettingsGroup.minimumSizeHint().height()+self.bottomButtonFrame.minimumSizeHint().height()+3
|
||||
@ -110,7 +121,6 @@ class ConfigDialog(QtGui.QDialog):
|
||||
self.setFixedSize(self.sizeHint())
|
||||
self.moreToggling = False
|
||||
self.setFixedWidth(self.minimumSizeHint().width())
|
||||
self.executablepathCombobox.setFixedWidth(self.mediapathTextbox.width())
|
||||
|
||||
def openHelp(self):
|
||||
self.QtGui.QDesktopServices.openUrl(QUrl("http://syncplay.pl/guide/client/"))
|
||||
@ -372,6 +382,8 @@ class ConfigDialog(QtGui.QDialog):
|
||||
self.config["mediaSearchDirectories"] = utils.convertMultilineStringToList(self.mediasearchTextEdit.toPlainText())
|
||||
self.config["trustedDomains"] = utils.convertMultilineStringToList(self.trusteddomainsTextEdit.toPlainText())
|
||||
|
||||
if self.serverpassTextbox.isEnabled():
|
||||
self.config['password'] = self.serverpassTextbox.text()
|
||||
self.processWidget(self, lambda w: self.saveValues(w))
|
||||
if self.hostCombobox.currentText():
|
||||
self.config['host'] = self.hostCombobox.currentText() if ":" in self.hostCombobox.currentText() else self.hostCombobox.currentText() + ":" + unicode(constants.DEFAULT_PORT)
|
||||
@ -386,6 +398,7 @@ class ConfigDialog(QtGui.QDialog):
|
||||
self.config['file'] = os.path.abspath(self.mediapathTextbox.text())
|
||||
else:
|
||||
self.config['file'] = unicode(self.mediapathTextbox.text())
|
||||
self.config['publicServers'] = self.publicServerAddresses
|
||||
|
||||
self.pressedclosebutton = False
|
||||
self.close()
|
||||
@ -415,6 +428,16 @@ class ConfigDialog(QtGui.QDialog):
|
||||
self.executablepathCombobox.setEditText(dropfilepath)
|
||||
else:
|
||||
self.mediapathTextbox.setText(dropfilepath)
|
||||
self.mediapathTextbox.show()
|
||||
self.mediapathLabel.show()
|
||||
self.mediabrowseButton.show()
|
||||
if not self.showmoreCheckbox.isChecked():
|
||||
newHeight = self.connectionSettingsGroup.minimumSizeHint().height() + self.mediaplayerSettingsGroup.minimumSizeHint().height() + self.bottomButtonFrame.minimumSizeHint().height() + 3
|
||||
if self.error:
|
||||
newHeight += self.errorLabel.height() + 3
|
||||
self.stackedFrame.setFixedHeight(newHeight)
|
||||
self.adjustSize()
|
||||
self.setFixedSize(self.sizeHint())
|
||||
|
||||
def processWidget(self, container, torun):
|
||||
for widget in container.children():
|
||||
@ -514,8 +537,12 @@ class ConfigDialog(QtGui.QDialog):
|
||||
if self.publicServers:
|
||||
i = 0
|
||||
for publicServer in self.publicServers:
|
||||
self.hostCombobox.addItem(publicServer[1])
|
||||
self.hostCombobox.setItemData(i, publicServer[0], Qt.ToolTipRole)
|
||||
serverTitle = publicServer[0]
|
||||
serverAddressPort = publicServer[1]
|
||||
self.hostCombobox.addItem(serverAddressPort)
|
||||
self.hostCombobox.setItemData(i, serverTitle, Qt.ToolTipRole)
|
||||
if not serverAddressPort in self.publicServerAddresses:
|
||||
self.publicServerAddresses.append(serverAddressPort)
|
||||
i += 1
|
||||
self.hostCombobox.setEditable(True)
|
||||
self.hostCombobox.setEditText(host)
|
||||
@ -531,6 +558,7 @@ class ConfigDialog(QtGui.QDialog):
|
||||
self.defaultroomTextbox = QLineEdit(self)
|
||||
self.usernameLabel = QLabel(getMessage("name-label"), self)
|
||||
self.serverpassTextbox = QLineEdit(self)
|
||||
self.serverpassTextbox.setText(self.storedPassword)
|
||||
self.defaultroomLabel = QLabel(getMessage("room-label"), self)
|
||||
|
||||
self.hostLabel.setObjectName("host")
|
||||
@ -538,7 +566,9 @@ class ConfigDialog(QtGui.QDialog):
|
||||
self.usernameLabel.setObjectName("name")
|
||||
self.usernameTextbox.setObjectName("name")
|
||||
self.serverpassLabel.setObjectName("password")
|
||||
self.serverpassTextbox.setObjectName("password")
|
||||
self.serverpassTextbox.setObjectName(constants.LOAD_SAVE_MANUALLY_MARKER + "password")
|
||||
self.hostCombobox.editTextChanged.connect(self.updatePasswordVisibilty)
|
||||
self.hostCombobox.currentIndexChanged.connect(self.updatePasswordVisibilty)
|
||||
self.defaultroomLabel.setObjectName("room")
|
||||
self.defaultroomTextbox.setObjectName("room")
|
||||
|
||||
@ -566,11 +596,12 @@ class ConfigDialog(QtGui.QDialog):
|
||||
self.executableiconImage = QtGui.QImage()
|
||||
self.executableiconLabel = QLabel(self)
|
||||
self.executableiconLabel.setMinimumWidth(16)
|
||||
self.executableiconLabel.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
|
||||
self.executablepathCombobox = QtGui.QComboBox(self)
|
||||
self.executablepathCombobox.setEditable(True)
|
||||
self.executablepathCombobox.currentIndexChanged.connect(self.updateExecutableIcon)
|
||||
self.executablepathCombobox.setEditText(self._tryToFillPlayerPath(config['playerPath'], playerpaths))
|
||||
self.executablepathCombobox.setFixedWidth(165)
|
||||
self.executablepathCombobox.setFixedWidth(250)
|
||||
self.executablepathCombobox.editTextChanged.connect(self.updateExecutableIcon)
|
||||
|
||||
self.executablepathLabel = QLabel(getMessage("executable-path-label"), self)
|
||||
@ -1111,7 +1142,7 @@ class ConfigDialog(QtGui.QDialog):
|
||||
self.tabListWidget.addItem(QtGui.QListWidgetItem(QtGui.QIcon(self.resourcespath + u"cog.png"),getMessage("misc-label")))
|
||||
self.tabListLayout.addWidget(self.tabListWidget)
|
||||
self.tabListFrame.setLayout(self.tabListLayout)
|
||||
self.tabListFrame.setFixedWidth(self.tabListFrame.minimumSizeHint().width())
|
||||
self.tabListFrame.setFixedWidth(self.tabListFrame.minimumSizeHint().width() + constants.TAB_PADDING)
|
||||
self.tabListWidget.setStyleSheet(constants.STYLE_TABLIST)
|
||||
|
||||
self.tabListWidget.currentItemChanged.connect(self.tabChange)
|
||||
@ -1136,7 +1167,6 @@ class ConfigDialog(QtGui.QDialog):
|
||||
def showEvent(self, *args, **kwargs):
|
||||
self.ensureTabListIsVisible()
|
||||
self.setFixedWidth(self.minimumSizeHint().width())
|
||||
self.executablepathCombobox.setFixedWidth(self.mediapathTextbox.width())
|
||||
|
||||
def clearGUIData(self, leaveMore=False):
|
||||
settings = QSettings("Syncplay", "PlayerList")
|
||||
@ -1168,8 +1198,22 @@ class ConfigDialog(QtGui.QDialog):
|
||||
for server in self.publicServers:
|
||||
self.hostCombobox.addItem(server[1])
|
||||
self.hostCombobox.setItemData(i, server[0], Qt.ToolTipRole)
|
||||
if not server[1] in self.publicServerAddresses:
|
||||
self.publicServerAddresses.append(server[1])
|
||||
i += 1
|
||||
self.hostCombobox.setEditText(currentServer)
|
||||
|
||||
def updatePasswordVisibilty(self):
|
||||
if (self.hostCombobox.currentText() == "" and self.serverpassTextbox.text() == "") or unicode(self.hostCombobox.currentText()) in self.publicServerAddresses:
|
||||
self.serverpassTextbox.setDisabled(True)
|
||||
self.serverpassTextbox.setReadOnly(True)
|
||||
if self.serverpassTextbox.text() != "":
|
||||
self.storedPassword = self.serverpassTextbox.text()
|
||||
self.serverpassTextbox.setText("")
|
||||
else:
|
||||
self.serverpassTextbox.setEnabled(True)
|
||||
self.serverpassTextbox.setReadOnly(False)
|
||||
self.serverpassTextbox.setText(self.storedPassword)
|
||||
|
||||
def __init__(self, config, playerpaths, error, defaultConfig):
|
||||
self.config = config
|
||||
@ -1179,6 +1223,7 @@ class ConfigDialog(QtGui.QDialog):
|
||||
self.config['resetConfig'] = False
|
||||
self.subitems = {}
|
||||
self.publicServers = None
|
||||
self.publicServerAddresses = []
|
||||
|
||||
self._playerProbeThread = GetPlayerIconThread()
|
||||
self._playerProbeThread.done.connect(self._updateExecutableIcon)
|
||||
@ -1211,6 +1256,7 @@ class ConfigDialog(QtGui.QDialog):
|
||||
self.mainLayout.setSpacing(0)
|
||||
self.mainLayout.setContentsMargins(0,0,0,0)
|
||||
|
||||
self.storedPassword = self.config['password']
|
||||
self.addBasicTab()
|
||||
self.addReadinessTab()
|
||||
self.addSyncTab()
|
||||
@ -1221,6 +1267,7 @@ class ConfigDialog(QtGui.QDialog):
|
||||
|
||||
self.mainLayout.addWidget(self.stackedFrame, 0, 1)
|
||||
self.addBottomLayout()
|
||||
self.updatePasswordVisibilty()
|
||||
|
||||
if self.getMoreState() == False:
|
||||
self.tabListFrame.hide()
|
||||
@ -1228,6 +1275,14 @@ class ConfigDialog(QtGui.QDialog):
|
||||
self.playerargsTextbox.hide()
|
||||
self.playerargsLabel.hide()
|
||||
self.runButton.hide()
|
||||
if self.mediapathTextbox.text() == "":
|
||||
self.mediapathTextbox.hide()
|
||||
self.mediapathLabel.hide()
|
||||
self.mediabrowseButton.hide()
|
||||
else:
|
||||
self.mediapathTextbox.show()
|
||||
self.mediapathLabel.show()
|
||||
self.mediabrowseButton.show()
|
||||
newHeight = self.connectionSettingsGroup.minimumSizeHint().height()+self.mediaplayerSettingsGroup.minimumSizeHint().height()+self.bottomButtonFrame.minimumSizeHint().height()+3
|
||||
if self.error:
|
||||
newHeight +=self.errorLabel.height()+3
|
||||
|
||||
@ -410,6 +410,9 @@ class MainWindow(QtGui.QMainWindow):
|
||||
def setFeatures(self, featureList):
|
||||
if not featureList["readiness"]:
|
||||
self.readyPushButton.setEnabled(False)
|
||||
if not featureList["chat"]:
|
||||
self.chatFrame.setEnabled(False)
|
||||
self.chatInput.setReadOnly(True)
|
||||
if not featureList["sharedPlaylists"]:
|
||||
self.playlistGroup.setEnabled(False)
|
||||
|
||||
@ -531,7 +534,7 @@ class MainWindow(QtGui.QMainWindow):
|
||||
filenameitem.setForeground(QtGui.QBrush(QtGui.QColor(constants.STYLE_DIFFERENTITEM_COLOR)))
|
||||
filenameitem.setFont(underlinefont)
|
||||
if not sameSize:
|
||||
if currentUser.file is not None and formatSize(user.file['size']) == formatSize(currentUser.file['size']):
|
||||
if formatSize(user.file['size']) == formatSize(currentUser.file['size']):
|
||||
filesizeitem = QtGui.QStandardItem(formatSize(user.file['size'],precise=True))
|
||||
filesizeitem.setFont(underlinefont)
|
||||
filesizeitem.setForeground(QtGui.QBrush(QtGui.QColor(constants.STYLE_DIFFERENTITEM_COLOR)))
|
||||
@ -570,8 +573,12 @@ class MainWindow(QtGui.QMainWindow):
|
||||
self._syncplayClient.playlist.undoPlaylistChange()
|
||||
|
||||
@needsClient
|
||||
def shufflePlaylist(self):
|
||||
self._syncplayClient.playlist.shufflePlaylist()
|
||||
def shuffleRemainingPlaylist(self):
|
||||
self._syncplayClient.playlist.shuffleRemainingPlaylist()
|
||||
|
||||
@needsClient
|
||||
def shuffleEntirePlaylist(self):
|
||||
self._syncplayClient.playlist.shuffleEntirePlaylist()
|
||||
|
||||
@needsClient
|
||||
def openPlaylistMenu(self, position):
|
||||
@ -603,7 +610,8 @@ class MainWindow(QtGui.QMainWindow):
|
||||
menu.addAction(QtGui.QPixmap(resourcespath + u"shield_add.png"),getMessage("addtrusteddomain-menu-label").format(domain), lambda: self.addTrustedDomain(domain))
|
||||
menu.addAction(QtGui.QPixmap(resourcespath + u"delete.png"), getMessage("removefromplaylist-menu-label"), lambda: self.deleteSelectedPlaylistItems())
|
||||
menu.addSeparator()
|
||||
menu.addAction(QtGui.QPixmap(resourcespath + u"arrow_switch.png"), getMessage("shuffleplaylist-menuu-label"), lambda: self.shufflePlaylist())
|
||||
menu.addAction(QtGui.QPixmap(resourcespath + u"arrow_switch.png"), getMessage("shuffleremainingplaylist-menu-label"), lambda: self.shuffleRemainingPlaylist())
|
||||
menu.addAction(QtGui.QPixmap(resourcespath + u"arrow_switch.png"), getMessage("shuffleentireplaylist-menuu-label"), lambda: self.shuffleEntirePlaylist())
|
||||
menu.addAction(QtGui.QPixmap(resourcespath + u"arrow_undo.png"), getMessage("undoplaylist-menu-label"), lambda: self.undoPlaylistChange())
|
||||
menu.addAction(QtGui.QPixmap(resourcespath + u"film_edit.png"), getMessage("editplaylist-menu-label"), lambda: self.openEditPlaylistDialog())
|
||||
menu.addAction(QtGui.QPixmap(resourcespath + u"film_add.png"),getMessage("addfilestoplaylist-menu-label"), lambda: self.OpenAddFilesToPlaylistDialog())
|
||||
|
||||
@ -42,8 +42,8 @@ def retry(ExceptionToCheck, tries=4, delay=3, backoff=2, logger=None):
|
||||
try_one_last_time = True
|
||||
while mtries > 1:
|
||||
try:
|
||||
#try_one_last_time = False
|
||||
return f(*args, **kwargs)
|
||||
try_one_last_time = False
|
||||
break
|
||||
except ExceptionToCheck, e:
|
||||
if logger:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user