Merge pull request #50 from Uriziel/areYouReady
User readiness indicator feature, update check, etc
This commit is contained in:
commit
8c99bcc794
@ -68,6 +68,7 @@ NSIS_SCRIPT_TEMPLATE = r"""
|
||||
LangString ^StartMenu $${LANG_ENGLISH} "Start Menu"
|
||||
LangString ^Desktop $${LANG_ENGLISH} "Desktop"
|
||||
LangString ^QuickLaunchBar $${LANG_ENGLISH} "Quick Launch Bar"
|
||||
LangString ^AutomaticUpdates $${LANG_ENGLISH} "Check for updates automatically"
|
||||
LangString ^UninstConfig $${LANG_ENGLISH} "Delete configuration file."
|
||||
|
||||
LangString ^SyncplayLanguage $${LANG_POLISH} "pl"
|
||||
@ -88,6 +89,7 @@ NSIS_SCRIPT_TEMPLATE = r"""
|
||||
LangString ^StartMenu $${LANG_RUSSIAN} "в меню Пуск"
|
||||
LangString ^Desktop $${LANG_RUSSIAN} "на рабочем столе"
|
||||
LangString ^QuickLaunchBar $${LANG_RUSSIAN} "в меню быстрого запуска"
|
||||
LangString ^AutomaticUpdates $${LANG_RUSSIAN} "Проверять обновления автоматически"; TODO: Confirm Russian translation ("Check for updates automatically")
|
||||
LangString ^UninstConfig $${LANG_RUSSIAN} "Удалить файл настроек."
|
||||
|
||||
LangString ^SyncplayLanguage $${LANG_GERMAN} "de"
|
||||
@ -98,6 +100,7 @@ NSIS_SCRIPT_TEMPLATE = r"""
|
||||
LangString ^StartMenu $${LANG_GERMAN} "Startmenü"
|
||||
LangString ^Desktop $${LANG_GERMAN} "Desktop"
|
||||
LangString ^QuickLaunchBar $${LANG_GERMAN} "Schnellstartleiste"
|
||||
LangString ^AutomaticUpdates $${LANG_GERMAN} "Automatisch nach Updates suchen"; TODO: Confirm German translation ("Check for updates automatically")
|
||||
LangString ^UninstConfig $${LANG_GERMAN} "Konfigurationsdatei löschen."
|
||||
|
||||
; Remove text to save space
|
||||
@ -117,11 +120,13 @@ NSIS_SCRIPT_TEMPLATE = r"""
|
||||
Var Icon_Syncplay_Handle
|
||||
Var CheckBox_Associate
|
||||
Var CheckBox_VLC
|
||||
Var CheckBox_AutomaticUpdates
|
||||
Var CheckBox_StartMenuShortcut
|
||||
Var CheckBox_DesktopShortcut
|
||||
Var CheckBox_QuickLaunchShortcut
|
||||
Var CheckBox_Associate_State
|
||||
Var CheckBox_VLC_State
|
||||
Var CheckBox_AutomaticUpdates_State
|
||||
Var CheckBox_StartMenuShortcut_State
|
||||
Var CheckBox_DesktopShortcut_State
|
||||
Var CheckBox_QuickLaunchShortcut_State
|
||||
@ -237,10 +242,10 @@ NSIS_SCRIPT_TEMPLATE = r"""
|
||||
$${NSD_CreateGroupBox} 1u 27u 264u 30u "$$(^DirSubText)"
|
||||
Pop $$GroupBox_DirSub
|
||||
|
||||
$${NSD_CreateLabel} 0u 111u 265u 8u "$$(^SpaceRequired)$$SizeMB"
|
||||
$${NSD_CreateLabel} 0u 122u 132 8u "$$(^SpaceRequired)$$SizeMB"
|
||||
Pop $$Label_Size
|
||||
|
||||
$${NSD_CreateLabel} 0u 122u 265u 8u "$$(^SpaceAvailable)$$AvailibleSpaceGiB.$$AvailibleSpaceGB"
|
||||
$${NSD_CreateLabel} 321u 122u 132 8u "$$(^SpaceAvailable)$$AvailibleSpaceGiB.$$AvailibleSpaceGB"
|
||||
Pop $$Label_Space
|
||||
|
||||
$${NSD_CreateCheckBox} 8u 59u 187u 10u "$$(^Associate)"
|
||||
@ -253,16 +258,20 @@ NSIS_SCRIPT_TEMPLATE = r"""
|
||||
$${NSD_CreateCheckBox} 8u 72u 250u 10u "$$(^VLC)"
|
||||
Pop $$CheckBox_VLC
|
||||
|
||||
$${NSD_CreateLabel} 8u 85u 187u 10u "$$(^Shortcut)"
|
||||
$${NSD_CreateCheckBox} 8u 85u 250u 10u "$$(^AutomaticUpdates)"
|
||||
Pop $$CheckBox_AutomaticUpdates
|
||||
$${NSD_Check} $$CheckBox_AutomaticUpdates
|
||||
|
||||
$${NSD_CreateLabel} 8u 98u 187u 10u "$$(^Shortcut)"
|
||||
Pop $$Label_Shortcut
|
||||
|
||||
$${NSD_CreateCheckbox} 8u 98u 60u 10u "$$(^StartMenu)"
|
||||
$${NSD_CreateCheckbox} 8u 111u 60u 10u "$$(^StartMenu)"
|
||||
Pop $$CheckBox_StartMenuShortcut
|
||||
|
||||
$${NSD_CreateCheckbox} 78u 98u 70u 10u "$$(^Desktop)"
|
||||
$${NSD_CreateCheckbox} 78u 111u 70u 10u "$$(^Desktop)"
|
||||
Pop $$CheckBox_DesktopShortcut
|
||||
|
||||
$${NSD_CreateCheckbox} 158u 98u 130u 10u "$$(^QuickLaunchBar)"
|
||||
$${NSD_CreateCheckbox} 158u 111u 130u 10u "$$(^QuickLaunchBar)"
|
||||
Pop $$CheckBox_QuickLaunchShortcut
|
||||
|
||||
$${If} $$CheckBox_Associate_State == $${BST_CHECKED}
|
||||
@ -287,6 +296,10 @@ NSIS_SCRIPT_TEMPLATE = r"""
|
||||
$${NSD_Check} $$CheckBox_QuickLaunchShortcut
|
||||
$${EndIf}
|
||||
|
||||
$${If} $$CheckBox_AutomaticUpdates_State == $${BST_CHECKED}
|
||||
$${NSD_Check} $$CheckBox_AutomaticUpdates
|
||||
$${EndIf}
|
||||
|
||||
nsDialogs::Show
|
||||
|
||||
$${NSD_FreeIcon} $$Icon_Syncplay_Handle
|
||||
@ -297,6 +310,7 @@ NSIS_SCRIPT_TEMPLATE = r"""
|
||||
$${NSD_GetText} $$Text_Directory $$INSTDIR
|
||||
$${NSD_GetState} $$CheckBox_Associate $$CheckBox_Associate_State
|
||||
$${NSD_GetState} $$CheckBox_VLC $$CheckBox_VLC_State
|
||||
$${NSD_GetState} $$CheckBox_AutomaticUpdates $$CheckBox_AutomaticUpdates_State
|
||||
$${NSD_GetState} $$CheckBox_StartMenuShortcut $$CheckBox_StartMenuShortcut_State
|
||||
$${NSD_GetState} $$CheckBox_DesktopShortcut $$CheckBox_DesktopShortcut_State
|
||||
$${NSD_GetState} $$CheckBox_QuickLaunchShortcut $$CheckBox_QuickLaunchShortcut_State
|
||||
@ -444,6 +458,11 @@ NSIS_SCRIPT_TEMPLATE = r"""
|
||||
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Syncplay" "NoRepair" 1
|
||||
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Syncplay" "EstimatedSize" "$$SizeHex"
|
||||
WriteINIStr $$APPDATA\syncplay.ini general language $$(^SyncplayLanguage)
|
||||
$${If} $$CheckBox_AutomaticUpdates_State == $${BST_CHECKED}
|
||||
WriteINIStr $$APPDATA\syncplay.ini general CheckForUpdatesAutomatically "True"
|
||||
$${Else}
|
||||
WriteINIStr $$APPDATA\syncplay.ini general CheckForUpdatesAutomatically "False"
|
||||
$${EndIf}
|
||||
FunctionEnd
|
||||
|
||||
Function un.installConfirm
|
||||
@ -624,7 +643,8 @@ guiIcons = ['resources/accept.png', 'resources/arrow_undo.png', 'resources/clock
|
||||
'resources/mpv.png','resources/vlc.png', 'resources/house.png', 'resources/film_link.png',
|
||||
'resources/eye.png', 'resources/comments.png', 'resources/cog_delete.png', 'resources/chevrons_right.png',
|
||||
'resources/user_key.png', 'resources/lock.png', 'resources/key_go.png', 'resources/page_white_key.png',
|
||||
'resources/tick.png', 'resources/lock_open.png'
|
||||
'resources/tick.png', 'resources/lock_open.png', 'resources/empty_checkbox.png', 'resources/tick_checkbox.png',
|
||||
'resources/world_explore.png', 'resources/application_get.png', 'resources/cog.png'
|
||||
]
|
||||
resources = ["resources/icon.ico", "resources/syncplay.png"]
|
||||
resources.extend(guiIcons)
|
||||
|
||||
BIN
resources/application_get.png
Normal file
BIN
resources/application_get.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 581 B |
BIN
resources/cog.png
Normal file
BIN
resources/cog.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 512 B |
BIN
resources/cross_checkbox.png
Normal file
BIN
resources/cross_checkbox.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 671 B |
BIN
resources/empty_checkbox.png
Normal file
BIN
resources/empty_checkbox.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 179 B |
@ -5,7 +5,7 @@
|
||||
Principal author: Etoh
|
||||
Other contributors: DerGenaue, jb
|
||||
Project: http://syncplay.pl/
|
||||
Version: 0.2.3
|
||||
Version: 0.2.4
|
||||
|
||||
Note:
|
||||
* This interface module is intended to be used in conjunction with Syncplay.
|
||||
@ -68,6 +68,9 @@ You may also need to re-copy the syncplay.lua file when you update VLC.
|
||||
display-osd: [placement on screen <center/left/right/top/bottom/top-left/top-right/bottom-left/bottom-right>], [duration in seconds], [message]
|
||||
? >> display-osd-error: no-input
|
||||
|
||||
display-secondary-osd: [placement on screen <center/left/right/top/bottom/top-left/top-right/bottom-left/bottom-right>], [duration in seconds], [message]
|
||||
? >> display-secondary-osd-error: no-input
|
||||
|
||||
load-file: [filepath]
|
||||
* >> load-file-attempted
|
||||
|
||||
@ -78,7 +81,7 @@ You may also need to re-copy the syncplay.lua file when you update VLC.
|
||||
|
||||
--]==========================================================================]
|
||||
|
||||
local connectorversion = "0.2.3"
|
||||
local connectorversion = "0.2.4"
|
||||
local durationdelay = 500000 -- Pause for get_duration command etc for increased reliability (uses microseconds)
|
||||
local loopsleepduration = 5000 -- Pause for every event loop (uses microseconds)
|
||||
local quitcheckfrequency = 20 -- Check whether VLC has closed every X loops
|
||||
@ -108,12 +111,18 @@ local newinputstate
|
||||
local oldtitle = 0
|
||||
local newtitle = 0
|
||||
|
||||
local channel1
|
||||
local channel2
|
||||
local l
|
||||
|
||||
local running = true
|
||||
|
||||
|
||||
function radixsafe_tonumber(str)
|
||||
-- Version of tonumber that works with any radix character (but not thousand seperators)
|
||||
-- Based on the public domain VLC common.lua us_tonumber() function
|
||||
str = string.gsub(tostring(str), "[^0-9]", ".")
|
||||
|
||||
str = string.gsub(tostring(str), "[^0-9]", ".")
|
||||
local s, i, d = string.match(str, "^([+-]?)(%d*)%.?(%d*)$")
|
||||
if not s or not i or not d then
|
||||
return nil
|
||||
@ -277,8 +286,8 @@ function set_time ( timetoset)
|
||||
end
|
||||
errormsg = set_var("time", radixsafe_tonumber(realtime))
|
||||
return errormsg
|
||||
else
|
||||
return noinput
|
||||
else
|
||||
return noinput
|
||||
end
|
||||
end
|
||||
|
||||
@ -379,17 +388,19 @@ function get_duration ()
|
||||
|
||||
if input then
|
||||
local item = vlc.input.item()
|
||||
if (item and item:duration()) then
|
||||
-- Try to get duration, which might not be available straight away
|
||||
local i = 0
|
||||
repeat
|
||||
vlc.misc.mwait(vlc.misc.mdate() + durationdelay)
|
||||
local i = 0
|
||||
response = 0
|
||||
repeat
|
||||
vlc.misc.mwait(vlc.misc.mdate() + durationdelay)
|
||||
if item and item:duration() then
|
||||
response = item:duration()
|
||||
i = i + 1
|
||||
until response > 0 or i > 5
|
||||
else
|
||||
errormsg = noinput
|
||||
end
|
||||
if response < 1 then
|
||||
response = 0
|
||||
end
|
||||
end
|
||||
i = i + 1
|
||||
until response > 1 or i > 5
|
||||
else
|
||||
errormsg = noinput
|
||||
end
|
||||
@ -400,11 +411,16 @@ end
|
||||
|
||||
function display_osd ( argument )
|
||||
-- [Used by display-osd command]
|
||||
|
||||
local errormsg
|
||||
local osdarray
|
||||
local input = vlc.object.input()
|
||||
if input then
|
||||
if input and vlc.osd and vlc.object.vout() then
|
||||
if not channel1 then
|
||||
channel1 = vlc.osd.channel_register()
|
||||
end
|
||||
if not channel2 then
|
||||
channel2 = vlc.osd.channel_register()
|
||||
end
|
||||
osdarray = get_args(argument,3)
|
||||
--position, duration, message -> message, , position, duration (converted from seconds to microseconds)
|
||||
local osdduration = radixsafe_tonumber(osdarray[2]) * 1000 * 1000
|
||||
@ -415,6 +431,28 @@ function display_osd ( argument )
|
||||
return errormsg
|
||||
end
|
||||
|
||||
function display_secondary_osd ( argument )
|
||||
-- [Used by display-secondary-osd command]
|
||||
local errormsg
|
||||
local osdarray
|
||||
local input = vlc.object.input()
|
||||
if input and vlc.osd and vlc.object.vout() then
|
||||
if not channel1 then
|
||||
channel1 = vlc.osd.channel_register()
|
||||
end
|
||||
if not channel2 then
|
||||
channel2 = vlc.osd.channel_register()
|
||||
end
|
||||
osdarray = get_args(argument,3)
|
||||
--position, duration, message -> message, , position, duration (converted from seconds to microseconds)
|
||||
local osdduration = radixsafe_tonumber(osdarray[2]) * 1000 * 1000
|
||||
vlc.osd.message(osdarray[3],channel2,osdarray[1],osdduration)
|
||||
else
|
||||
errormsg = noinput
|
||||
end
|
||||
return errormsg
|
||||
end
|
||||
|
||||
function load_file (filepath)
|
||||
-- [Used by load-file command]
|
||||
|
||||
@ -445,6 +483,7 @@ function do_command ( command, argument)
|
||||
elseif command == "set-rate" then errormsg = set_var("rate", radixsafe_tonumber(argument))
|
||||
elseif command == "set-title" then errormsg = set_var("title", radixsafe_tonumber(argument))
|
||||
elseif command == "display-osd" then errormsg = display_osd(argument)
|
||||
elseif command == "display-secondary-osd" then errormsg = display_secondary_osd(argument)
|
||||
elseif command == "load-file" then response = load_file(argument)
|
||||
elseif command == "close-vlc" then quit_vlc()
|
||||
else errormsg = unknowncommand
|
||||
@ -498,7 +537,7 @@ while running == true do
|
||||
--accept new connections and select active clients
|
||||
local quitcheckcounter = 0
|
||||
local fd = l:accept()
|
||||
local buffer, inputbuffer, responsebuffer = ""
|
||||
local buffer, inputbuffer, responsebuffer = "", "", ""
|
||||
while fd >= 0 and running == true do
|
||||
|
||||
-- handle read mode
|
||||
@ -560,7 +599,6 @@ while running == true do
|
||||
quitcheckcounter = 0
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
BIN
resources/tick_checkbox.png
Normal file
BIN
resources/tick_checkbox.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 556 B |
BIN
resources/world_explore.png
Normal file
BIN
resources/world_explore.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 987 B |
@ -1,3 +1,4 @@
|
||||
version = '1.3.0'
|
||||
milestone = 'Akki'
|
||||
milestone = 'Chami'
|
||||
release_number = '2'
|
||||
projectURL = 'http://syncplay.pl/'
|
||||
|
||||
@ -68,6 +68,7 @@ class SyncplayClient(object):
|
||||
self.serverVersion = "0.0.0"
|
||||
|
||||
self.lastLeftTime = 0
|
||||
self.lastPausedOnLeaveTime = None
|
||||
self.lastLeftUser = u""
|
||||
self.protocolFactory = SyncClientFactory(self)
|
||||
self.ui = UiManager(self, ui)
|
||||
@ -104,8 +105,9 @@ class SyncplayClient(object):
|
||||
self._userOffset = 0.0
|
||||
self._speedChanged = False
|
||||
self.behindFirstDetected = None
|
||||
self.autoPlay = False
|
||||
|
||||
self._warnings = self._WarningManager(self._player, self.userlist, self.ui)
|
||||
self._warnings = self._WarningManager(self._player, self.userlist, self.ui, self)
|
||||
if constants.LIST_RELATIVE_CONFIGS and self._config.has_key('loadedRelativePaths') and self._config['loadedRelativePaths']:
|
||||
paths = "; ".join(self._config['loadedRelativePaths'])
|
||||
self.ui.showMessage(getMessage("relative-config-notification").format(paths), noPlayer=True, noTimestamp=True)
|
||||
@ -125,6 +127,8 @@ class SyncplayClient(object):
|
||||
|
||||
def initPlayer(self, player):
|
||||
self._player = player
|
||||
if not self._player.secondaryOSDSupported:
|
||||
constants.OSD_WARNING_MESSAGE_DURATION = constants.NO_SECONDARY_OSD_WARNING_DURATION
|
||||
self.scheduleAskPlayer()
|
||||
|
||||
def scheduleAskPlayer(self, when=constants.PLAYER_ASK_DELAY):
|
||||
@ -158,6 +162,20 @@ class SyncplayClient(object):
|
||||
pauseChange, seeked = self._determinePlayerStateChange(paused, position)
|
||||
self._playerPosition = position
|
||||
self._playerPaused = paused
|
||||
if pauseChange and utils.meetsMinVersion(self.serverVersion, constants.USER_READY_MIN_VERSION):
|
||||
if not paused and not self.userlist.currentUser.isReady() and not self.userlist.areAllOtherUsersInRoomReady():
|
||||
paused = True
|
||||
self._player.setPaused(paused)
|
||||
self._playerPaused = paused
|
||||
self.changeReadyState(True, manuallyInitiated=True)
|
||||
pauseChange = False
|
||||
self.ui.showMessage(getMessage("ready-to-unpause-notification"))
|
||||
else:
|
||||
lastPausedDiff = time.time() - self.lastPausedOnLeaveTime if self.lastPausedOnLeaveTime else None
|
||||
if lastPausedDiff is not None and lastPausedDiff < constants.LAST_PAUSED_DIFF_THRESHOLD:
|
||||
self.lastPausedOnLeaveTime = None
|
||||
else:
|
||||
self.changeReadyState(not self.getPlayerPaused(), manuallyInitiated=False)
|
||||
if self._lastGlobalUpdate:
|
||||
self._lastPlayerUpdate = time.time()
|
||||
if (pauseChange or seeked) and self._protocol:
|
||||
@ -301,8 +319,10 @@ class SyncplayClient(object):
|
||||
self.ui.showMessage(getMessage("current-offset-notification").format(self._userOffset))
|
||||
|
||||
def onDisconnect(self):
|
||||
self.resetAutoPlayState()
|
||||
if self._config['pauseOnLeave']:
|
||||
self.setPaused(True)
|
||||
self.lastPausedOnLeaveTime = time.time()
|
||||
|
||||
def removeUser(self, username):
|
||||
if self.userlist.isUserInYourRoom(username):
|
||||
@ -379,13 +399,14 @@ class SyncplayClient(object):
|
||||
import random
|
||||
random.seed()
|
||||
random_number = random.randrange(1000, 9999)
|
||||
self.userlist.currentUser.username = "Anonymous" + str(random_number)
|
||||
self.userlist.currentUser.username = "Anonymous" + str(random_number) # Not localised as this would give away locale
|
||||
|
||||
def getUsername(self):
|
||||
return self.userlist.currentUser.username
|
||||
|
||||
def setRoom(self, roomName):
|
||||
self.userlist.currentUser.room = roomName
|
||||
self.resetAutoPlayState()
|
||||
|
||||
def sendRoom(self):
|
||||
room = self.userlist.currentUser.room
|
||||
@ -402,6 +423,8 @@ class SyncplayClient(object):
|
||||
self.identifyAsController(storedRoomPassword)
|
||||
|
||||
def connected(self):
|
||||
readyState = self._config['readyAtStart'] if self.userlist.currentUser.isReady() is None else self.userlist.currentUser.isReady()
|
||||
self._protocol.setReady(readyState, manuallyInitiated=False)
|
||||
self.reIdentifyAsController()
|
||||
|
||||
def getRoom(self):
|
||||
@ -470,15 +493,45 @@ class SyncplayClient(object):
|
||||
return wrapper
|
||||
return requireMinVersionDecorator
|
||||
|
||||
def changeAutoPlayState(self, newState):
|
||||
self.autoPlay = newState
|
||||
self.autoPlayCheck()
|
||||
|
||||
def autoPlayCheck(self):
|
||||
if self.autoPlay and self.userlist.currentUser.canControl() and self.userlist.isReadinessSupported() and self.userlist.areAllUsersInRoomReady():
|
||||
self.setPaused(False)
|
||||
|
||||
def resetAutoPlayState(self):
|
||||
self.autoPlay = False
|
||||
self.ui.updateAutoPlayState(False)
|
||||
|
||||
@requireMinServerVersion(constants.USER_READY_MIN_VERSION)
|
||||
def toggleReady(self, manuallyInitiated=True):
|
||||
self._protocol.setReady(not self.userlist.currentUser.isReady(), manuallyInitiated)
|
||||
|
||||
@requireMinServerVersion(constants.USER_READY_MIN_VERSION)
|
||||
def changeReadyState(self, newState, manuallyInitiated=True):
|
||||
oldState = self.userlist.currentUser.isReady()
|
||||
if newState != oldState:
|
||||
self.toggleReady(manuallyInitiated)
|
||||
|
||||
def setReady(self, username, isReady, manuallyInitiated=True):
|
||||
oldReadyState = self.userlist.isReady(username)
|
||||
if oldReadyState is None:
|
||||
oldReadyState = False
|
||||
self.userlist.setReady(username, isReady)
|
||||
self.ui.userListChange()
|
||||
if oldReadyState != isReady:
|
||||
self._warnings.checkReadyStates()
|
||||
|
||||
@requireMinServerVersion(constants.CONTROLLED_ROOMS_MIN_VERSION)
|
||||
def createControlledRoom(self, roomName):
|
||||
controlPassword = utils.RandomStringGenerator.generate_room_password()
|
||||
self.ui.showMessage(u"Attempting to create controlled room '{}' with password '{}'...".format(roomName, controlPassword))
|
||||
self.lastControlPasswordAttempt = controlPassword
|
||||
self._protocol.requestControlledRoom(roomName, controlPassword)
|
||||
|
||||
def controlledRoomCreated(self, roomName, controlPassword):
|
||||
self.ui.showMessage(u"Created controlled room '{}' with password '{}'. Please save this information for future reference!".format(roomName, controlPassword))
|
||||
self.ui.showMessage(getMessage("created-controlled-room-notification").format(roomName, controlPassword))
|
||||
self.setRoom(roomName)
|
||||
self.sendRoom()
|
||||
self._protocol.requestControlledRoom(roomName, controlPassword)
|
||||
@ -498,7 +551,8 @@ class SyncplayClient(object):
|
||||
self._protocol.requestControlledRoom(self.getRoom(), controlPassword)
|
||||
|
||||
def controllerIdentificationError(self, username, room):
|
||||
self.ui.showErrorMessage(getMessage("failed-to-identify-as-controller-notification").format(username))
|
||||
if username == self.getUsername():
|
||||
self.ui.showErrorMessage(getMessage("failed-to-identify-as-controller-notification").format(username))
|
||||
|
||||
def controllerIdentificationSuccess(self, username, roomname):
|
||||
self.userlist.setUserAsController(username)
|
||||
@ -517,55 +571,132 @@ class SyncplayClient(object):
|
||||
if self.controlpasswords.has_key(room):
|
||||
return self.controlpasswords[room]
|
||||
|
||||
def checkForUpdate(self, userInitiated):
|
||||
try:
|
||||
import urllib, syncplay, sys, messages, json
|
||||
params = urllib.urlencode({'version': syncplay.version, 'milestone': syncplay.milestone, 'release_number': syncplay.release_number,
|
||||
'language': messages.messages["CURRENT"], 'platform': sys.platform, 'userInitiated': userInitiated})
|
||||
|
||||
f = urllib.urlopen(constants.SYNCPLAY_UPDATE_URL.format(params))
|
||||
response = f.read()
|
||||
response = response.replace("<p>","").replace("</p>","").replace("<br />","").replace("“","\"").replace("”","\"") # Fix Wordpress
|
||||
response = json.loads(response)
|
||||
return response["version-status"], response["version-message"] if response.has_key("version-message") else None, response["version-url"] if response.has_key("version-url") else None
|
||||
except:
|
||||
return "failed", getMessage("update-check-failed-notification").format(syncplay.version), constants.SYNCPLAY_DOWNLOAD_URL
|
||||
|
||||
class _WarningManager(object):
|
||||
def __init__(self, player, userlist, ui):
|
||||
def __init__(self, player, userlist, ui, client):
|
||||
self._client = client
|
||||
self._player = player
|
||||
self._userlist = userlist
|
||||
self._ui = ui
|
||||
self._warnings = {
|
||||
"room-files-not-same": {
|
||||
"timer": task.LoopingCall(self.__displayMessageOnOSD,
|
||||
"room-files-not-same",),
|
||||
"displayedFor": 0,
|
||||
},
|
||||
"alone-in-the-room": {
|
||||
"timer": task.LoopingCall(self.__displayMessageOnOSD,
|
||||
"alone-in-the-room",),
|
||||
"displayedFor": 0,
|
||||
},
|
||||
}
|
||||
"room-file-differences": {
|
||||
"timer": task.LoopingCall(self.__displayMessageOnOSD, "room-file-differences",
|
||||
lambda: self._checkRoomForSameFiles(OSDOnly=True),),
|
||||
"displayedFor": 0,
|
||||
},
|
||||
"alone-in-the-room": {
|
||||
"timer": task.LoopingCall(self.__displayMessageOnOSD, "alone-in-the-room",
|
||||
lambda: self._checkIfYouReAloneInTheRoom(OSDOnly=True)),
|
||||
"displayedFor": 0,
|
||||
},
|
||||
"not-all-ready": {
|
||||
"timer": task.LoopingCall(self.__displayMessageOnOSD, "not-all-ready",
|
||||
lambda: self.checkReadyStates(),),
|
||||
"displayedFor": 0,
|
||||
},
|
||||
}
|
||||
self.pausedTimer = task.LoopingCall(self.__displayPausedMessagesOnOSD)
|
||||
self.pausedTimer.start(constants.WARNING_OSD_MESSAGES_LOOP_INTERVAL, True)
|
||||
|
||||
def checkWarnings(self):
|
||||
self._checkIfYouReAloneInTheRoom()
|
||||
self._checkRoomForSameFiles()
|
||||
self._checkIfYouReAloneInTheRoom(OSDOnly=False)
|
||||
self._checkRoomForSameFiles(OSDOnly=False)
|
||||
self.checkReadyStates()
|
||||
|
||||
def _checkRoomForSameFiles(self):
|
||||
def _checkRoomForSameFiles(self, OSDOnly):
|
||||
if not self._userlist.areAllFilesInRoomSame():
|
||||
self._ui.showMessage(getMessage("room-files-not-same"), True)
|
||||
if constants.SHOW_OSD_WARNINGS and not self._warnings["room-files-not-same"]['timer'].running:
|
||||
self._warnings["room-files-not-same"]['timer'].start(constants.WARNING_OSD_MESSAGES_LOOP_INTERVAL, True)
|
||||
elif self._warnings["room-files-not-same"]['timer'].running:
|
||||
self._warnings["room-files-not-same"]['timer'].stop()
|
||||
self._displayReadySameWarning()
|
||||
if not OSDOnly and constants.SHOW_OSD_WARNINGS and not self._warnings["room-file-differences"]['timer'].running:
|
||||
self._warnings["room-file-differences"]['timer'].start(constants.WARNING_OSD_MESSAGES_LOOP_INTERVAL, True)
|
||||
elif self._warnings["room-file-differences"]['timer'].running:
|
||||
self._warnings["room-file-differences"]['timer'].stop()
|
||||
|
||||
def _checkIfYouReAloneInTheRoom(self):
|
||||
def _checkIfYouAreOnlyUserInRoomWhoSupportsReadiness(self):
|
||||
self._userlist._onlyUserInRoomWhoSupportsReadiness()
|
||||
|
||||
def _checkIfYouReAloneInTheRoom(self, OSDOnly):
|
||||
if self._userlist.areYouAloneInRoom():
|
||||
self._ui.showMessage(getMessage("alone-in-the-room"), True)
|
||||
if constants.SHOW_OSD_WARNINGS and not self._warnings["alone-in-the-room"]['timer'].running:
|
||||
self._warnings["alone-in-the-room"]['timer'].start(constants.WARNING_OSD_MESSAGES_LOOP_INTERVAL, True)
|
||||
self._ui.showOSDMessage(getMessage("alone-in-the-room"), constants.WARNING_OSD_MESSAGES_LOOP_INTERVAL, secondaryOSD=True)
|
||||
if not OSDOnly:
|
||||
self._ui.showMessage(getMessage("alone-in-the-room"), True)
|
||||
if constants.SHOW_OSD_WARNINGS and not self._warnings["alone-in-the-room"]['timer'].running:
|
||||
self._warnings["alone-in-the-room"]['timer'].start(constants.WARNING_OSD_MESSAGES_LOOP_INTERVAL, True)
|
||||
elif self._warnings["alone-in-the-room"]['timer'].running:
|
||||
self._warnings["alone-in-the-room"]['timer'].stop()
|
||||
|
||||
def __displayMessageOnOSD(self, warningName):
|
||||
def checkReadyStates(self):
|
||||
if not self._client:
|
||||
return
|
||||
if self._client.getPlayerPaused() or not self._userlist.currentUser.isReady():
|
||||
self._warnings["not-all-ready"]["displayedFor"] = 0
|
||||
if self._userlist.areYouAloneInRoom() or not self._userlist.currentUser.canControl():
|
||||
if self._warnings["not-all-ready"]['timer'].running:
|
||||
self._warnings["not-all-ready"]['timer'].stop()
|
||||
elif not self._userlist.areAllUsersInRoomReady():
|
||||
self._displayReadySameWarning()
|
||||
if constants.SHOW_OSD_WARNINGS and not self._warnings["not-all-ready"]['timer'].running:
|
||||
self._warnings["not-all-ready"]['timer'].start(constants.WARNING_OSD_MESSAGES_LOOP_INTERVAL, True)
|
||||
elif self._warnings["not-all-ready"]['timer'].running:
|
||||
self._warnings["not-all-ready"]['timer'].stop()
|
||||
self._displayReadySameWarning()
|
||||
elif self._client.getPlayerPaused() or not self._userlist.currentUser.isReady():
|
||||
self._displayReadySameWarning()
|
||||
|
||||
def _displayReadySameWarning(self):
|
||||
if not self._client._player:
|
||||
return
|
||||
osdMessage = None
|
||||
if not self._userlist.areAllFilesInRoomSame():
|
||||
fileDifferencesMessage = getMessage("room-file-differences").format(self._userlist.getFileDifferencesForRoom())
|
||||
if self._userlist.currentUser.canControl() and self._userlist.isReadinessSupported():
|
||||
if self._userlist.areAllUsersInRoomReady():
|
||||
osdMessage = u"{}{}{}".format(fileDifferencesMessage, self._client._player.osdMessageSeparator, getMessage("all-users-ready").format(self._userlist.readyUserCount()))
|
||||
else:
|
||||
osdMessage = u"{}{}{}".format(fileDifferencesMessage, self._client._player.osdMessageSeparator, getMessage("not-all-ready").format(self._userlist.usersInRoomNotReady()))
|
||||
else:
|
||||
osdMessage = fileDifferencesMessage
|
||||
elif self._userlist.isReadinessSupported():
|
||||
if self._userlist.areAllUsersInRoomReady():
|
||||
osdMessage = getMessage("all-users-ready").format(self._userlist.readyUserCount())
|
||||
else:
|
||||
osdMessage = getMessage("not-all-ready").format(self._userlist.usersInRoomNotReady())
|
||||
if osdMessage:
|
||||
self._ui.showOSDMessage(osdMessage, constants.WARNING_OSD_MESSAGES_LOOP_INTERVAL, secondaryOSD=True)
|
||||
|
||||
def __displayMessageOnOSD(self, warningName, warningFunction):
|
||||
if constants.OSD_WARNING_MESSAGE_DURATION > self._warnings[warningName]["displayedFor"]:
|
||||
self._ui.showOSDMessage(getMessage(warningName), constants.WARNING_OSD_MESSAGES_LOOP_INTERVAL)
|
||||
warningFunction()
|
||||
self._warnings[warningName]["displayedFor"] += constants.WARNING_OSD_MESSAGES_LOOP_INTERVAL
|
||||
else:
|
||||
self._warnings[warningName]["displayedFor"] = 0
|
||||
self._warnings[warningName]["timer"].stop()
|
||||
|
||||
try:
|
||||
self._warnings[warningName]["timer"].stop()
|
||||
except:
|
||||
pass
|
||||
|
||||
def __displayPausedMessagesOnOSD(self):
|
||||
if self._client and self._client._player and self._client.getPlayerPaused():
|
||||
self._checkRoomForSameFiles(OSDOnly=True)
|
||||
self.checkReadyStates()
|
||||
elif not self._userlist.currentUser.isReady(): # CurrentUser should always be reminded they are set to not ready
|
||||
self.checkReadyStates()
|
||||
|
||||
class SyncplayUser(object):
|
||||
def __init__(self, username=None, room=None, file_=None):
|
||||
self.ready = None
|
||||
self.username = username
|
||||
self.room = room
|
||||
self.file = file_
|
||||
@ -573,10 +704,10 @@ class SyncplayUser(object):
|
||||
|
||||
def setFile(self, filename, duration, size):
|
||||
file_ = {
|
||||
"name": filename,
|
||||
"duration": duration,
|
||||
"size":size
|
||||
}
|
||||
"name": filename,
|
||||
"duration": duration,
|
||||
"size": size
|
||||
}
|
||||
self.file = file_
|
||||
|
||||
def isFileSame(self, file_):
|
||||
@ -611,6 +742,12 @@ class SyncplayUser(object):
|
||||
else:
|
||||
return False
|
||||
|
||||
def isReady(self):
|
||||
return self.ready
|
||||
|
||||
def setReady(self, ready):
|
||||
self.ready = ready
|
||||
|
||||
class SyncplayUserlist(object):
|
||||
def __init__(self, ui, client):
|
||||
self.currentUser = SyncplayUser()
|
||||
@ -619,6 +756,14 @@ class SyncplayUserlist(object):
|
||||
self._client = client
|
||||
self._roomUsersChanged = True
|
||||
|
||||
def isReadinessSupported(self):
|
||||
if not utils.meetsMinVersion(self._client.serverVersion,constants.USER_READY_MIN_VERSION):
|
||||
return False
|
||||
elif self.onlyUserInRoomWhoSupportsReadiness():
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def isRoomSame(self, room):
|
||||
if room and self.currentUser.room and self.currentUser.room == room:
|
||||
return True
|
||||
@ -644,30 +789,49 @@ class SyncplayUserlist(object):
|
||||
message += getMessage("playing-notification/room-addendum").format(room)
|
||||
self.ui.showMessage(message, hideFromOSD)
|
||||
if self.currentUser.file and not self.currentUser.isFileSame(file_) and self.currentUser.room == room:
|
||||
message = getMessage("file-different-notification").format(username)
|
||||
self.ui.showMessage(message, hideFromOSD)
|
||||
differences = []
|
||||
differentName = not utils.sameFilename(self.currentUser.file['name'], file_['name'])
|
||||
differentSize = not utils.sameFilesize(self.currentUser.file['size'], file_['size'])
|
||||
differentDuration = not utils.sameFileduration(self.currentUser.file['duration'], file_['duration'])
|
||||
if differentName:
|
||||
differences.append("filename")
|
||||
if differentSize:
|
||||
differences.append("size")
|
||||
if differentDuration:
|
||||
differences.append("duration")
|
||||
message = getMessage("file-differences-notification") + ", ".join(differences)
|
||||
self.ui.showMessage(message, hideFromOSD)
|
||||
message = getMessage("file-differences-notification").format(self.getFileDifferencesForUser(self.currentUser.file, file_))
|
||||
self.ui.showMessage(message, True)
|
||||
|
||||
def getFileDifferencesForUser(self, currentUserFile, otherUserFile):
|
||||
differences = []
|
||||
differentName = not utils.sameFilename(currentUserFile['name'], otherUserFile['name'])
|
||||
differentSize = not utils.sameFilesize(currentUserFile['size'], otherUserFile['size'])
|
||||
differentDuration = not utils.sameFileduration(currentUserFile['duration'], otherUserFile['duration'])
|
||||
if differentName: differences.append(getMessage("file-difference-filename"))
|
||||
if differentSize: differences.append(getMessage("file-difference-filesize"))
|
||||
if differentDuration: differences.append(getMessage("file-difference-duration"))
|
||||
return ", ".join(differences)
|
||||
|
||||
def addUser(self, username, room, file_, noMessage=False, isController=None):
|
||||
def getFileDifferencesForRoom(self):
|
||||
differences = []
|
||||
differentName = False
|
||||
differentSize = False
|
||||
differentDuration = False
|
||||
for otherUser in self._users.itervalues():
|
||||
if otherUser.room == self.currentUser.room:
|
||||
if not utils.sameFilename(self.currentUser.file['name'], otherUser.file['name']):
|
||||
differentName = True
|
||||
if not utils.sameFilesize(self.currentUser.file['size'], otherUser.file['size']):
|
||||
differentSize = True
|
||||
if not utils.sameFileduration(self.currentUser.file['duration'], otherUser.file['duration']):
|
||||
differentDuration = True
|
||||
if differentName: differences.append(getMessage("file-difference-filename"))
|
||||
if differentSize: differences.append(getMessage("file-difference-filesize"))
|
||||
if differentDuration: differences.append(getMessage("file-difference-duration"))
|
||||
return ", ".join(differences)
|
||||
|
||||
def addUser(self, username, room, file_, noMessage=False, isController=None, isReady=None):
|
||||
if username == self.currentUser.username:
|
||||
if isController is not None:
|
||||
self.currentUser.setControllerStatus(isController)
|
||||
self.currentUser.setReady(isReady)
|
||||
return
|
||||
user = SyncplayUser(username, room, file_)
|
||||
if isController is not None:
|
||||
user.setControllerStatus(isController)
|
||||
self._users[username] = user
|
||||
user.setReady(isReady)
|
||||
|
||||
if not noMessage:
|
||||
self.__showUserChangeMessage(username, room, file_)
|
||||
self.userListChange(room)
|
||||
@ -716,11 +880,46 @@ class SyncplayUserlist(object):
|
||||
user = self._users[username]
|
||||
user.setControllerStatus(True)
|
||||
|
||||
def areAllFilesInRoomSame(self):
|
||||
def areAllUsersInRoomReady(self):
|
||||
if not self.currentUser.canControl():
|
||||
return True
|
||||
if not self.currentUser.isReady():
|
||||
return False
|
||||
for user in self._users.itervalues():
|
||||
if user.room == self.currentUser.room and user.file and not self.currentUser.isFileSame(user.file):
|
||||
if user.canControl():
|
||||
return False
|
||||
if user.room == self.currentUser.room and user.isReady() == False:
|
||||
return False
|
||||
return True
|
||||
|
||||
def areAllOtherUsersInRoomReady(self):
|
||||
for user in self._users.itervalues():
|
||||
if user.room == self.currentUser.room and user.isReady() == False:
|
||||
return False
|
||||
return True
|
||||
|
||||
def readyUserCount(self):
|
||||
readyCount = 0
|
||||
if self.currentUser.isReady():
|
||||
readyCount += 1
|
||||
for user in self._users.itervalues():
|
||||
if user.room == self.currentUser.room and user.isReady():
|
||||
readyCount += 1
|
||||
return readyCount
|
||||
|
||||
def usersInRoomNotReady(self):
|
||||
notReady = []
|
||||
if not self.currentUser.isReady():
|
||||
notReady.append(self.currentUser.username)
|
||||
for user in self._users.itervalues():
|
||||
if user.room == self.currentUser.room and user.isReady() == False:
|
||||
notReady.append(user.username)
|
||||
return ", ".join(notReady)
|
||||
|
||||
def areAllFilesInRoomSame(self):
|
||||
if self.currentUser.file:
|
||||
for user in self._users.itervalues():
|
||||
if user.room == self.currentUser.room and user.file and not self.currentUser.isFileSame(user.file):
|
||||
if user.canControl():
|
||||
return False
|
||||
return True
|
||||
|
||||
def areYouAloneInRoom(self):
|
||||
@ -728,6 +927,12 @@ class SyncplayUserlist(object):
|
||||
if user.room == self.currentUser.room:
|
||||
return False
|
||||
return True
|
||||
|
||||
def onlyUserInRoomWhoSupportsReadiness(self):
|
||||
for user in self._users.itervalues():
|
||||
if user.room == self.currentUser.room and user.isReady() is not None:
|
||||
return False
|
||||
return True
|
||||
|
||||
def isUserInYourRoom(self, username):
|
||||
for user in self._users.itervalues():
|
||||
@ -744,6 +949,22 @@ class SyncplayUserlist(object):
|
||||
return True
|
||||
return False
|
||||
|
||||
def isReady(self, username):
|
||||
if self.currentUser.username == username:
|
||||
return self.currentUser.isReady()
|
||||
|
||||
for user in self._users.itervalues():
|
||||
if user.username == username:
|
||||
return user.isReady()
|
||||
return None
|
||||
|
||||
def setReady(self, username, isReady):
|
||||
if self.currentUser.username == username:
|
||||
self.currentUser.setReady(isReady)
|
||||
elif self._users.has_key(username):
|
||||
self._users[username].setReady(isReady)
|
||||
self._client.autoPlayCheck()
|
||||
|
||||
def userListChange(self, room = None):
|
||||
if room is not None and self.isRoomSame(room):
|
||||
self._roomUsersChanged = True
|
||||
@ -766,6 +987,7 @@ class SyncplayUserlist(object):
|
||||
rooms[self.currentUser.room].append(self.currentUser)
|
||||
rooms = self.sortList(rooms)
|
||||
self.ui.showUserList(self.currentUser, rooms)
|
||||
self._client.autoPlayCheck()
|
||||
|
||||
def clearList(self):
|
||||
self._users = {}
|
||||
@ -780,22 +1002,44 @@ class UiManager(object):
|
||||
def __init__(self, client, ui):
|
||||
self._client = client
|
||||
self.__ui = ui
|
||||
self.lastPrimaryOSDMessage = None
|
||||
self.lastPrimaryOSDEndTime = None
|
||||
self.lastSecondaryOSDMessage = None
|
||||
self.lastSecondaryOSDEndTime = None
|
||||
self.lastError = ""
|
||||
|
||||
def showDebugMessage(self, message):
|
||||
if constants.DEBUG_MODE and message.rstrip():
|
||||
print "{}{}".format(time.strftime(constants.UI_TIME_FORMAT, time.localtime()),message.rstrip())
|
||||
|
||||
def showMessage(self, message, noPlayer=False, noTimestamp=False):
|
||||
if not noPlayer: self.showOSDMessage(message)
|
||||
def showMessage(self, message, noPlayer=False, noTimestamp=False, secondaryOSD=False):
|
||||
if not noPlayer: self.showOSDMessage(message, duration=constants.OSD_DURATION, secondaryOSD=secondaryOSD)
|
||||
self.__ui.showMessage(message, noTimestamp)
|
||||
|
||||
def updateAutoPlayState(self, newState):
|
||||
self.__ui.updateAutoPlayState(newState)
|
||||
|
||||
def showUserList(self, currentUser, rooms):
|
||||
self.__ui.showUserList(currentUser, rooms)
|
||||
|
||||
def showOSDMessage(self, message, duration=constants.OSD_DURATION):
|
||||
if constants.SHOW_OSD and self._client._player:
|
||||
self._client._player.displayMessage(message, duration * 1000)
|
||||
def showOSDMessage(self, message, duration=constants.OSD_DURATION, secondaryOSD=False):
|
||||
if secondaryOSD and not constants.SHOW_OSD_WARNINGS:
|
||||
return
|
||||
if not self._client._player:
|
||||
return
|
||||
if constants.SHOW_OSD and self._client and self._client._player:
|
||||
if not self._client._player.secondaryOSDSupported:
|
||||
if secondaryOSD:
|
||||
self.lastSecondaryOSDMessage = message
|
||||
self.lastSecondaryOSDEndTime = time.time() + constants.NO_SECONDARY_OSD_WARNING_DURATION
|
||||
if self.lastPrimaryOSDEndTime and time.time() < self.lastPrimaryOSDEndTime:
|
||||
message = u"{}{}{}".format(message, self._client._player.osdMessageSeparator, self.lastPrimaryOSDMessage)
|
||||
else:
|
||||
self.lastPrimaryOSDMessage = message
|
||||
self.lastPrimaryOSDEndTime = time.time() + constants.OSD_DURATION
|
||||
if self.lastSecondaryOSDEndTime and time.time() < self.lastSecondaryOSDEndTime:
|
||||
message = u"{}{}{}".format(self.lastSecondaryOSDMessage, self._client._player.osdMessageSeparator, message)
|
||||
self._client._player.displayMessage(message, duration * 1000, secondaryOSD)
|
||||
|
||||
def setControllerStatus(self, username, isController):
|
||||
self.__ui.setControllerStatus(username, isController)
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
# You might want to change these
|
||||
DEFAULT_PORT = 8999
|
||||
OSD_DURATION = 3
|
||||
OSD_WARNING_MESSAGE_DURATION = 15
|
||||
MPC_OSD_POSITION = 2 #Right corner, 1 for left
|
||||
OSD_WARNING_MESSAGE_DURATION = 5
|
||||
NO_SECONDARY_OSD_WARNING_DURATION = 13
|
||||
MPC_OSD_POSITION = 1 #Right corner, 1 for left
|
||||
MPLAYER_OSD_LEVEL = 1
|
||||
UI_TIME_FORMAT = "[%X] "
|
||||
CONFIG_NAMES = [".syncplay", "syncplay.ini"] #Syncplay searches first to last
|
||||
@ -12,7 +13,6 @@ RECENT_CLIENT_THRESHOLD = "1.2.9" #This and higher considered 'recent' clients
|
||||
WARN_OLD_CLIENTS = True #Use MOTD to inform old clients to upgrade
|
||||
LIST_RELATIVE_CONFIGS = True # Print list of relative configs loaded
|
||||
SHOW_CONTACT_INFO = True # Displays dev contact details below list in GUI
|
||||
SHOW_BUTTON_LABELS = True # If disabled, only shows icons for main GUI buttons
|
||||
SHOW_TOOLTIPS = True
|
||||
WARN_ABOUT_MISSING_STRINGS = False # (If debug mode is enabled)
|
||||
FALLBACK_INITIAL_LANGUAGE = "en"
|
||||
@ -28,6 +28,7 @@ SHOW_DURATION_NOTIFICATION = True
|
||||
DEBUG_MODE = False
|
||||
|
||||
#Changing these might be ok
|
||||
AUTOMATIC_UPDATE_CHECK_FREQUENCY = 7 * 86400 # Days converted into seconds
|
||||
DEFAULT_REWIND_THRESHOLD = 4
|
||||
MINIMUM_REWIND_THRESHOLD = 3
|
||||
DEFAULT_FASTFORWARD_THRESHOLD = 5
|
||||
@ -45,9 +46,9 @@ PROTOCOL_TIMEOUT = 12.5
|
||||
RECONNECT_RETRIES = 10
|
||||
SERVER_STATE_INTERVAL = 1
|
||||
WARNING_OSD_MESSAGES_LOOP_INTERVAL = 1
|
||||
MERGE_PLAYPAUSE_BUTTONS = False
|
||||
SYNC_ON_PAUSE = True # Client seek to global position - subtitles may disappear on some media players
|
||||
#Usually there's no need to adjust these
|
||||
LAST_PAUSED_DIFF_THRESHOLD = 2
|
||||
FILENAME_STRIP_REGEX = u"[-~_\.\[\](): ]"
|
||||
CONTROL_PASSWORD_STRIP_REGEX = u"[^a-zA-Z0-9\-]"
|
||||
ROOM_NAME_STRIP_REGEX = u"^(\+)(?P<roomnamebase>.*)(:)(\w{12})$"
|
||||
@ -58,10 +59,12 @@ COMMANDS_ROOM = ["r", "room"]
|
||||
COMMANDS_HELP = ['help', 'h', '?', '/?', r'\?']
|
||||
COMMANDS_CREATE = ['c','create']
|
||||
COMMANDS_AUTH = ['a','auth']
|
||||
COMMANDS_TOGGLE = ['t','toggle']
|
||||
MPC_MIN_VER = "1.6.4"
|
||||
VLC_MIN_VERSION = "2.0.0"
|
||||
VLC_INTERFACE_MIN_VERSION = "0.2.1"
|
||||
VLC_INTERFACE_MIN_VERSION = "0.2.4"
|
||||
CONTROLLED_ROOMS_MIN_VERSION = "1.3.0"
|
||||
USER_READY_MIN_VERSION = "1.3.0"
|
||||
MPC_PATHS = [
|
||||
r"c:\program files (x86)\mpc-hc\mpc-hc.exe",
|
||||
r"c:\program files\mpc-hc\mpc-hc.exe",
|
||||
@ -115,7 +118,10 @@ STYLE_SUBCHECKBOX = "QCheckBox, QLabel {{ margin-left: 6px; padding-left: 21px;
|
||||
STYLE_SUBLABEL = "QCheckBox, QLabel {{ margin-left: 6px; padding-left: 16px; background:url('{}') left no-repeat }}" #Graphic path
|
||||
STYLE_ERRORLABEL = "QLabel { color : black; border-style: outset; border-width: 2px; border-radius: 7px; border-color: red; padding: 2px; background: #FFAAAA; }"
|
||||
STYLE_SUCCESSLABEL = "QLabel { color : black; border-style: outset; border-width: 2px; border-radius: 7px; border-color: green; padding: 2px; background: #AAFFAA; }"
|
||||
STYLE_READY_PUSHBUTTON = "QPushButton { text-align: left; padding: 10px 5px 10px 5px;}"
|
||||
STYLE_AUTO_PLAY_PUSHBUTTON = "QPushButton { text-align: left; padding: 5px 5px 5px 5px; }"
|
||||
STYLE_NOTIFICATIONBOX = "Username { color: #367AA9; font-weight:bold; }"
|
||||
STYLE_CONTACT_INFO = u"<span style=\"color: grey\"><strong><small>{}</span><br /><br />" # Contact info message
|
||||
STYLE_USERNAME = "color: #367AA9; font-weight:bold;"
|
||||
STYLE_ERRORNOTIFICATION = "color: red;"
|
||||
STYLE_DIFFERENTITEM_COLOR = 'red'
|
||||
@ -137,7 +143,7 @@ VLC_SLAVE_NONOSX_ARGS = ['--no-one-instance', '--no-one-instance-when-started-fr
|
||||
MPLAYER_ANSWER_REGEX = "^ANS_([a-zA-Z_-]+)=(.+)$|^(Exiting)\.\.\. \((.+)\)$"
|
||||
VLC_ANSWER_REGEX = r"(?:^(?P<command>[a-zA-Z_]+)(?:\: )?(?P<argument>.*))"
|
||||
UI_COMMAND_REGEX = r"^(?P<command>[^\ ]+)(?:\ (?P<parameter>.+))?"
|
||||
UI_OFFSET_REGEX = r"^(?:o|offset)\ ?(?P<sign>[/+-])?(?P<time>\d{1,4}(?:[^\d\.](?:\d{1,6})){0,2}(?:\.(?:\d{1,3}))?)$"
|
||||
UI_OFFSET_REGEX = r"^(?:o|offset)\ ?(?P<sign>[/+-])?(?P<time>\d{1,9}(?:[^\d\.](?:\d{1,9})){0,2}(?:\.(?:\d{1,3}))?)$"
|
||||
UI_SEEK_REGEX = r"^(?:s|seek)?\ ?(?P<sign>[+-])?(?P<time>\d{1,4}(?:[^\d\.](?:\d{1,6})){0,2}(?:\.(?:\d{1,3}))?)$"
|
||||
PARSE_TIME_REGEX = r'(:?(?:(?P<hours>\d+?)[^\d\.])?(?:(?P<minutes>\d+?))?[^\d\.])?(?P<seconds>\d+?)(?:\.(?P<miliseconds>\d+?))?$'
|
||||
SERVER_MAX_TEMPLATE_LENGTH = 10000
|
||||
@ -152,3 +158,6 @@ CONFIG_NAME_MARKER = ":"
|
||||
CONFIG_VALUE_MARKER = "="
|
||||
USERITEM_CONTROLLER_ROLE = 0
|
||||
USERITEM_READY_ROLE = 1
|
||||
|
||||
SYNCPLAY_UPDATE_URL = u"http://syncplay.pl/checkforupdate?{}" # Params
|
||||
SYNCPLAY_DOWNLOAD_URL = "http://syncplay.pl/download/"
|
||||
@ -7,7 +7,7 @@ en = {
|
||||
# Client notifications
|
||||
"config-cleared-notification" : "Settings cleared. Changes will be saved when you store a valid configuration.",
|
||||
|
||||
"relative-config-notification" : "Loaded relative configuration file(s): {}",
|
||||
"relative-config-notification" : u"Loaded relative configuration file(s): {}",
|
||||
|
||||
"connection-attempt-notification" : "Attempting to connect to {}:{}", # Port, IP
|
||||
"reconnection-attempt-notification" : "Connection with server lost, attempting to reconnect",
|
||||
@ -21,31 +21,48 @@ en = {
|
||||
"slowdown-notification" : "Slowing down due to time difference with <{}>", # User
|
||||
"revert-notification" : "Reverting speed back to normal",
|
||||
|
||||
"pause-notification" : "<{}> paused", # User
|
||||
"unpause-notification" : "<{}> unpaused", # User
|
||||
"seek-notification" : "<{}> jumped from {} to {}", # User, from time, to time
|
||||
"pause-notification" : u"<{}> paused", # User
|
||||
"unpause-notification" : u"<{}> unpaused", # User
|
||||
"seek-notification" : u"<{}> jumped from {} to {}", # User, from time, to time
|
||||
|
||||
"current-offset-notification" : "Current offset: {} seconds", # Offset
|
||||
|
||||
"room-join-notification" : "<{}> has joined the room: '{}'", # User
|
||||
"left-notification" : "<{}> has left", # User
|
||||
"left-paused-notification" : "<{}> left, <{}> paused", # User who left, User who paused
|
||||
"playing-notification" : "<{}> is playing '{}' ({})", # User, file, duration
|
||||
"playing-notification/room-addendum" : " in room: '{}'", # Room
|
||||
"room-join-notification" : u"<{}> has joined the room: '{}'", # User
|
||||
"left-notification" : u"<{}> has left", # User
|
||||
"left-paused-notification" : u"<{}> left, <{}> paused", # User who left, User who paused
|
||||
"playing-notification" : u"<{}> is playing '{}' ({})", # User, file, duration
|
||||
"playing-notification/room-addendum" : u" in room: '{}'", # Room
|
||||
|
||||
"identifying-as-controller-notification" : u"Identifying as room controller with password '{}'...",
|
||||
"failed-to-identify-as-controller-notification" : u"<{}> failed to identify as a room controller.",
|
||||
"authenticated-as-controller-notification" : u"<{}> authenticated as a room controller",
|
||||
"not-all-ready" : u"Not ready: {}", # Usernames
|
||||
"all-users-ready" : u"Everyone is ready ({} users)", #Number of ready users
|
||||
"ready-to-unpause-notification" : u"You are now set as ready - unpause again to unpause",
|
||||
|
||||
"identifying-as-controller-notification" : u"Identifying as room operator with password '{}'...",
|
||||
"failed-to-identify-as-controller-notification" : u"<{}> failed to identify as a room operator.",
|
||||
"authenticated-as-controller-notification" : u"<{}> authenticated as a room operator",
|
||||
"created-controlled-room-notification" : u"Created managed room '{}' with password '{}'. Please save this information for future reference!", # RoomName, controlPassword
|
||||
|
||||
"file-different-notification" : "File you are playing appears to be different from <{}>'s", # User
|
||||
"file-differences-notification" : "Your file differs in the following way(s): ",
|
||||
"room-files-not-same" : "Not all files played in the room are the same",
|
||||
"alone-in-the-room": "You're alone in the room",
|
||||
"file-differences-notification" : u"Your file differs in the following way(s): {}", # Differences
|
||||
"room-file-differences" : u"File differences: {}", # File differences (filename, size, and/or duration)
|
||||
"file-difference-filename" : u"name",
|
||||
"file-difference-filesize" : u"size",
|
||||
"file-difference-duration" : u"duration",
|
||||
"alone-in-the-room": u"You're alone in the room",
|
||||
|
||||
"different-filesize-notification" : " (their file size is different from yours!)",
|
||||
"file-played-by-notification" : "File: {} is being played by:", # File
|
||||
"different-filesize-notification" : u" (their file size is different from yours!)",
|
||||
"userlist-playing-notification" : u"{} is playing:", #Username
|
||||
"file-played-by-notification" : u"File: {} is being played by:", # File
|
||||
"no-file-played-notification" : u"{} is not playing a file", # Username
|
||||
"notplaying-notification" : "People who are not playing any file:",
|
||||
"userlist-room-notification" : "In room '{}':", # Room
|
||||
"userlist-room-notification" : u"In room '{}':", # Room
|
||||
"userlist-file-notification" : "File",
|
||||
"controller-userlist-userflag" : "Operator",
|
||||
"ready-userlist-userflag" : "Ready",
|
||||
|
||||
"update-check-failed-notification" : u"Could not automatically check whether Syncplay {} is up to date. Want to visit http://syncplay.pl/ to manually check for updates?", #Syncplay version
|
||||
"syncplay-uptodate-notification" : u"Syncplay is up to date",
|
||||
"syncplay-updateavailable-notification" : u"A new version of Syncplay is available. Do you want to download it?",
|
||||
|
||||
"mplayer-file-required-notification" : "Syncplay using mplayer requires you to provide file when starting",
|
||||
"mplayer-file-required-notification/example" : "Usage example: syncplay [options] [url|path/]filename",
|
||||
@ -59,13 +76,15 @@ en = {
|
||||
"commandlist-notification/pause" : "\tp - toggle pause",
|
||||
"commandlist-notification/seek" : "\t[s][+-]time - seek to the given value of time, if + or - is not specified it's absolute time in seconds or min:sec",
|
||||
"commandlist-notification/help" : "\th - this help",
|
||||
"commandlist-notification/create" : "\tc [name] - create controlled room using name of current room",
|
||||
"commandlist-notification/auth" : "\ta [password] - authenticate as room controller with controller password",
|
||||
"commandlist-notification/toggle" : u"\tt - toggles whether you are ready to watch or not",
|
||||
"commandlist-notification/create" : "\tc [name] - create managed room using name of current room",
|
||||
"commandlist-notification/auth" : "\ta [password] - authenticate as room operator with controller password",
|
||||
"syncplay-version-notification" : "Syncplay version: {}", # syncplay.version
|
||||
"more-info-notification" : "More info available at: {}", # projectURL
|
||||
|
||||
"gui-data-cleared-notification" : "Syncplay has cleared the path and window state data used by the GUI.",
|
||||
"language-changed-msgbox-label" : "Language will be changed when you run Syncplay.",
|
||||
"promptforupdate-label" : u"Is it okay for Syncplay to automatically check for updates from time to time?",
|
||||
|
||||
"vlc-version-mismatch": "Warning: You are running VLC version {}, but Syncplay is designed to run on VLC {} and above.", # VLC version, VLC min version
|
||||
"vlc-interface-version-mismatch": "Warning: You are running version {} of the Syncplay interface module for VLC, but Syncplay is designed to run with version {} and above.", # VLC interface version, VLC interface min version
|
||||
@ -106,6 +125,9 @@ en = {
|
||||
"vlc-failed-versioncheck": "This version of VLC is not supported by Syncplay. Please use VLC 2.",
|
||||
"vlc-failed-other" : "When trying to load the syncplay.lua interface script VLC has provided the following error: {}", # Syncplay Error
|
||||
|
||||
"invalid-seek-value" : u"Invalid seek value",
|
||||
"invalid-offset-value" : u"Invalid offset value",
|
||||
|
||||
# Client arguments
|
||||
"argument-description" : 'Solution to synchronize playback of multiple MPlayer and MPC-HC instances over the network.',
|
||||
"argument-epilog" : 'If no options supplied _config values will be used',
|
||||
@ -151,32 +173,36 @@ en = {
|
||||
"privacy-dontsend-option" : "Don't send",
|
||||
"filename-privacy-label" : "Filename information:",
|
||||
"filesize-privacy-label" : "File size information:",
|
||||
"checkforupdatesautomatically-label" : "Check for Syncplay updates automatically",
|
||||
"slowondesync-label" : "Slow down on minor desync (not supported on MPC-HC)",
|
||||
"rewindondesync-label" : "Rewind on major desync (highly recommended)",
|
||||
"rewindondesync-label" : "Rewind on major desync (recommended)",
|
||||
"fastforwardondesync-label" : "Fast-forward if lagging behind (recommended)",
|
||||
"dontslowdownwithme-label" : "Never slow down or rewind others (experimental)",
|
||||
"pauseonleave-label" : "Pause when user leaves (e.g. if they are disconnected)",
|
||||
"forceguiprompt-label" : "Don't always show this dialog", # (Inverted)
|
||||
"readyatstart-label" : "Set me as 'ready to watch' by default",
|
||||
"forceguiprompt-label" : "Don't always show the Syncplay configuration window", # (Inverted)
|
||||
"nostore-label" : "Don't store this configuration", # (Inverted)
|
||||
"showosd-label" : "Enable OSD Messages",
|
||||
|
||||
"showosdwarnings-label" : "Include warnings (e.g. when files are different)",
|
||||
"showosdwarnings-label" : "Include warnings (e.g. when files are different, users not ready)",
|
||||
"showsameroomosd-label" : "Include events in your room",
|
||||
"shownoncontrollerosd-label" : "Include events from non-controllers in controlled rooms",
|
||||
"shownoncontrollerosd-label" : "Include events from non-operators in managed rooms",
|
||||
"showdifferentroomosd-label" : "Include events in other rooms",
|
||||
"showslowdownosd-label" :"Include slowing down / reverting notifications",
|
||||
"showcontactinfo-label" : "Show contact info box",
|
||||
"language-label" : "Language",
|
||||
"automatic-language" : "Automatic ({})", # Automatic language #
|
||||
"language-label" : "Language:",
|
||||
"automatic-language" : "Default ({})", # Default language
|
||||
"showdurationnotification-label" : "Warn about media duration mismatches",
|
||||
"basics-label" : "Basics",
|
||||
"misc-label" : u"Misc",
|
||||
"core-behaviour-title" : "Core room behaviour",
|
||||
"syncplay-internals-title" : u"Syncplay internals",
|
||||
"sync-label" : "Sync",
|
||||
"sync-lagging-title" : "If others are lagging behind...",
|
||||
"sync-other-title" : "Other sync options",
|
||||
"sync-otherslagging-title" : "If others are lagging behind...",
|
||||
"sync-youlaggging-title" : "If you are lagging behind...",
|
||||
"messages-label" : "Messages",
|
||||
"messages-osd-title" : "On-screen Display settings",
|
||||
"messages-other-title" : "Other display settings",
|
||||
"privacy-label" : "Privacy",
|
||||
"privacy-label" : "Privacy", # Currently unused, but will be brought back if more space is needed in Misc tab
|
||||
"privacy-title" : "Privacy settings",
|
||||
|
||||
"help-label" : "Help",
|
||||
@ -184,14 +210,18 @@ en = {
|
||||
"run-label" : "Run Syncplay",
|
||||
"storeandrun-label" : "Store configuration and run Syncplay",
|
||||
|
||||
"contact-label" : "Have an idea, bug report or feedback? E-mail <a href=\"mailto:dev@syncplay.pl\">dev@syncplay.pl</a>, chat via the <a href=\"https://webchat.freenode.net/?channels=#syncplay\">#Syncplay IRC channel</a> on irc.freenode.net or <a href=\"https://github.com/Uriziel/syncplay/issues/new\">raise an issue via GitHub</a>. Also check out <a href=\"http://syncplay.pl/\">http://syncplay.pl/</a> for info, help and updates.",
|
||||
"contact-label" : "Feel free to e-mail <a href=\"mailto:dev@syncplay.pl\"><nobr>dev@syncplay.pl</nobr></a>, chat via the <a href=\"https://webchat.freenode.net/?channels=#syncplay\"><nobr>#Syncplay IRC channel</nobr></a> on irc.freenode.net, <a href=\"https://github.com/Uriziel/syncplay/issues/new\"><nobr>raise an issue</nobr></a> via GitHub or visit <a href=\"http://syncplay.pl/\"><nobr>http://syncplay.pl/</nobr></a>",
|
||||
|
||||
"joinroom-guibuttonlabel" : "Join room",
|
||||
"seektime-guibuttonlabel" : "Seek to time",
|
||||
"undoseek-guibuttonlabel" : "Undo seek",
|
||||
"togglepause-guibuttonlabel" : "Toggle pause",
|
||||
"play-guibuttonlabel" : "Play",
|
||||
"pause-guibuttonlabel" : "Pause",
|
||||
"joinroom-menu-label" : "Join room",
|
||||
"seektime-menu-label" : "Seek to time",
|
||||
"undoseek-menu-label" : "Undo seek",
|
||||
"play-menu-label" : "Play",
|
||||
"pause-menu-label" : "Pause",
|
||||
"playbackbuttons-menu-label" : u"Show playback buttons",
|
||||
"autoplay-menu-label" : u"Show auto-play button",
|
||||
"autoplay-guipushbuttonlabel" : u"Auto-play when everyone is ready",
|
||||
|
||||
"ready-guipushbuttonlabel" : u"I'm ready to watch!",
|
||||
|
||||
"roomuser-heading-label" : "Room / User",
|
||||
"size-heading-label" : "Size",
|
||||
@ -199,31 +229,35 @@ en = {
|
||||
"filename-heading-label" : "Filename",
|
||||
"notifications-heading-label" : "Notifications",
|
||||
"userlist-heading-label" : "List of who is playing what",
|
||||
"othercommands-heading-label" : "Other commands",
|
||||
"room-heading-label" : "Room",
|
||||
"seek-heading-label" : "Seek",
|
||||
|
||||
"browseformedia-label" : "Browse for media files",
|
||||
|
||||
"file-menu-label" : "&File", # & precedes shortcut key
|
||||
"openmedia-menu-label" : "&Open media file",
|
||||
"openstreamurl-menu-label" : "Open &media stream URL",
|
||||
"exit-menu-label" : "E&xit",
|
||||
"advanced-menu-label" : "&Advanced",
|
||||
"window-menu-label" : "&Window",
|
||||
"setoffset-menu-label" : "Set &offset",
|
||||
"createcontrolledroom-menu-label" : "&Create controlled room",
|
||||
"identifyascontroller-menu-label" : "&Identify as room controller",
|
||||
"createcontrolledroom-menu-label" : "&Create managed room",
|
||||
"identifyascontroller-menu-label" : "&Identify as room operator",
|
||||
|
||||
"playback-menu-label" : u"&Playback",
|
||||
|
||||
"help-menu-label" : "&Help",
|
||||
"userguide-menu-label" : "Open user &guide",
|
||||
"update-menu-label" : "Check for &update",
|
||||
|
||||
"setoffset-msgbox-label" : "Set offset",
|
||||
"offsetinfo-msgbox-label" : "Offset (see http://syncplay.pl/guide/ for usage instructions):",
|
||||
|
||||
"promptforstreamurl-msgbox-label" : "Open media stream URL",
|
||||
"promptforstreamurlinfo-msgbox-label" : "Stream URL",
|
||||
|
||||
"createcontrolledroom-msgbox-label" : "Create controlled room",
|
||||
"controlledroominfo-msgbox-label" : "Enter name of controlled room\r\n(see http://syncplay.pl/guide/ for usage instructions):",
|
||||
"createcontrolledroom-msgbox-label" : "Create managed room",
|
||||
"controlledroominfo-msgbox-label" : "Enter name of managed room\r\n(see http://syncplay.pl/guide/ for usage instructions):",
|
||||
|
||||
"identifyascontroller-msgbox-label" : "Identify as Room Controller",
|
||||
"identifyascontroller-msgbox-label" : "Identify as room operator",
|
||||
"identifyinfo-msgbox-label" : "Enter controller password for this room\r\n(see http://syncplay.pl/guide/ for usage instructions):",
|
||||
|
||||
"megabyte-suffix" : " MB",
|
||||
@ -241,38 +275,35 @@ en = {
|
||||
"more-tooltip" : "Display less frequently used settings.",
|
||||
"slowdown-threshold-tooltip" : "Time ahead of slowest client before temporarily reducing playback speed (default: {} secs).".format(constants.DEFAULT_SLOWDOWN_KICKIN_THRESHOLD),
|
||||
"rewind-threshold-tooltip" : "Time ahead slowest client before seeking to get back in sync (default: {} secs).".format(constants.DEFAULT_REWIND_THRESHOLD),
|
||||
"fastforward-threshold-tooltip" : "Time behind room controller before seeking to get back in sync (default: {} secs).".format(constants.DEFAULT_FASTFORWARD_THRESHOLD),
|
||||
"fastforward-threshold-tooltip" : "Time behind room operator before seeking to get back in sync (default: {} secs).".format(constants.DEFAULT_FASTFORWARD_THRESHOLD),
|
||||
"filename-privacy-tooltip" : "Privacy mode for sending currently playing filename to server.",
|
||||
"filesize-privacy-tooltip" : "Privacy mode for sending size of currently playing file to server.",
|
||||
"privacy-sendraw-tooltip" : "Send this information without obfuscation. This is the default option with most functionality.",
|
||||
"privacy-sendhashed-tooltip" : "Send a hashed version of the information, making it less visible to other clients.",
|
||||
"privacy-dontsend-tooltip" : "Do not send this information to the server. This provides for maximum privacy.",
|
||||
"checkforupdatesautomatically-tooltip" : "Regularly check with the Syncplay website to see whether a new version of Syncplay is available.",
|
||||
"slowondesync-tooltip" : "Reduce playback rate temporarily when needed to bring you back in sync with other viewers. Not supported on MPC-HC.",
|
||||
"dontslowdownwithme-tooltip" : "Means others do not get slowed down or rewinded if your playback is lagging. Useful for room controllers.",
|
||||
"dontslowdownwithme-tooltip" : "Means others do not get slowed down or rewinded if your playback is lagging. Useful for room operators.",
|
||||
"pauseonleave-tooltip" : "Pause playback if you get disconnected or someone leaves from your room.",
|
||||
"readyatstart-tooltip" : "Set yourself as 'ready' at start (otherwise you are set as 'not ready' until you change your readiness state)",
|
||||
"forceguiprompt-tooltip" : "Configuration dialogue is not shown when opening a file with Syncplay.", # (Inverted)
|
||||
"nostore-tooltip" : "Run Syncplay with the given configuration, but do not permanently store the changes.", # (Inverted)
|
||||
"rewindondesync-tooltip" : "Jump back when needed to get back in sync. Disabling this option can result in major desyncs!",
|
||||
"fastforwardondesync-tooltip" : "Jump forward when out of sync with room controller (or your pretend position if 'Never slow down or rewind others' enabled).",
|
||||
"fastforwardondesync-tooltip" : "Jump forward when out of sync with room operator (or your pretend position if 'Never slow down or rewind others' enabled).",
|
||||
"showosd-tooltip" : "Sends Syncplay messages to media player OSD.",
|
||||
"showosdwarnings-tooltip" : "Show warnings if playing different file, alone in room.",
|
||||
"showosdwarnings-tooltip" : "Show warnings if playing different file, alone in room, users not ready, etc.",
|
||||
"showsameroomosd-tooltip" : "Show OSD notifications for events relating to room user is in.",
|
||||
"shownoncontrollerosd-tooltip" : "Show OSD notifications for events relating to non-controllers who are in controlled rooms.",
|
||||
"shownoncontrollerosd-tooltip" : "Show OSD notifications for events relating to non-operators who are in managed rooms.",
|
||||
"showdifferentroomosd-tooltip" : "Show OSD notifications for events relating to room user is not in.",
|
||||
"showslowdownosd-tooltip" :"Show notifications of slowing down / reverting on time difference.",
|
||||
"showcontactinfo-tooltip" : "Show information box about contacting Syncplay developers in main Syncplay window.",
|
||||
"showdurationnotification-tooltip" : "Useful for when a segment in a multi-part file is missing, but can result in false positives.",
|
||||
"language-tooltip" : u"Language to be used by Syncplay.",
|
||||
|
||||
"help-tooltip" : "Opens the Syncplay.pl user guide.",
|
||||
"reset-tooltip" : "Reset all settings to the default configuration.",
|
||||
|
||||
"togglepause-tooltip" : "Pause/unpause media.",
|
||||
"play-tooltip" : "Unpause media.",
|
||||
"pause-tooltip" : "Pause media.",
|
||||
"undoseek-tooltip" : "Seek to where you were before the most recent seek.",
|
||||
"joinroom-tooltip" : "Leave current room and joins specified room.",
|
||||
"seektime-tooltip" : "Jump to specified time (in seconds / min:sec). Use +/- for relative seek.",
|
||||
"seektime-msgbox-label" : "Jump to specified time (in seconds / min:sec). Use +/- for relative seek.",
|
||||
|
||||
# In-userlist notes (GUI)
|
||||
"differentsize-note" : "Different size!",
|
||||
@ -296,7 +327,8 @@ en = {
|
||||
"server-port-argument" : 'server TCP port',
|
||||
"server-password-argument" : 'server password',
|
||||
"server-isolate-room-argument" : 'should rooms be isolated?',
|
||||
"server-salt-argument" : "random string used to generate controlled room passwords",
|
||||
"server-salt-argument" : "random string used to generate managed room passwords",
|
||||
"server-disable-ready-argument" : u"disable readiness feature",
|
||||
"server-motd-argument": "path to file from which motd will be fetched",
|
||||
"server-messed-up-motd-unescaped-placeholders": "Message of the Day has unescaped placeholders. All $ signs should be doubled ($$).",
|
||||
"server-messed-up-motd-too-long": "Message of the Day is too long - maximum of {} chars, {} given.",
|
||||
@ -327,7 +359,7 @@ ru = {
|
||||
"retrying-notification" : u"%s, следующая попытка через %d секунд(ы)...", # Seconds
|
||||
|
||||
"rewind-notification" : u"Перемотано из-за разницы во времени с <{}>", # User
|
||||
"fastforward-notification" : "Fast-forwarded due to time difference with <{}>", # User # TODO: Translate into Russian
|
||||
"fastforward-notification" : u"Fast-forwarded due to time difference with <{}>", # User # TODO: Translate into Russian
|
||||
"slowdown-notification" : u"Воспроизведение замедлено из-за разницы во времени с <{}>", # User
|
||||
"revert-notification" : u"Возвращаемся к нормальной скорости воспроизведения",
|
||||
|
||||
@ -343,19 +375,36 @@ ru = {
|
||||
"playing-notification" : u"<{}> включил '{}' ({})", # User, file, duration
|
||||
"playing-notification/room-addendum" : u" в комнате: '{}'", # Room
|
||||
|
||||
"identifying-as-controller-notification" : u"Identifying as room controller with password '{}'...", # TODO: Translate into Russian
|
||||
"failed-to-identify-as-controller-notification" : u"<{}> failed to identify as a room controller.", # TODO: Translate into Russian
|
||||
"authenticated-as-controller-notification" : u"<{}> authenticated as a room controller", # TODO: Translate into Russian
|
||||
"not-all-ready" : u"Not ready: {}", # Usernames # TODO: Translate into Russian
|
||||
"all-users-ready" : u"Everyone is ready ({} users)", #Number of ready users # TODO: Translate into Russian
|
||||
"ready-to-unpause-notification" : u"You are now set as ready - unpause again to unpause", # TODO: Translate into Russian
|
||||
|
||||
"identifying-as-controller-notification" : u"Identifying as room operator with password '{}'...", # TODO: Translate into Russian
|
||||
"failed-to-identify-as-controller-notification" : u"<{}> failed to identify as a room operator.", # TODO: Translate into Russian
|
||||
"authenticated-as-controller-notification" : u"<{}> authenticated as a room operator", # TODO: Translate into Russian
|
||||
"created-controlled-room-notification" : u"Created managed room '{}' with password '{}'. Please save this information for future reference!", # RoomName, controlPassword # TODO: Translate into Russian
|
||||
|
||||
"file-different-notification" : u"Вероятно, файл, который Вы смотрите, отличается от того, который смотрит <{}>.", # User
|
||||
"file-differences-notification" : u"Ваш файл отличается: ",
|
||||
"room-files-not-same" : u"Не все пользователи в этой комнате смотрят один и тот же файл.",
|
||||
"file-differences-notification" : u"Ваш файл отличается: {}", # Differences
|
||||
"room-file-differences" : u"File differences: {}", # File differences (filename, size, and/or duration)
|
||||
"file-difference-filename" : u"name", # TODO: Translate into Russian
|
||||
"file-difference-filesize" : u"size", # TODO: Translate into Russian
|
||||
"file-difference-duration" : u"duration", # TODO: Translate into Russian
|
||||
"alone-in-the-room" : u"В этой комнате кроме Вас никого нет.",
|
||||
|
||||
"different-filesize-notification" : u" (размер Вашего файла не совпадает с размером их файла!)",
|
||||
"userlist-playing-notification" : u"{} is playing:", #Username # TODO: Translate into Russian (same as playing-notification?)
|
||||
"file-played-by-notification" : u"Файл: {} просматривают:", # File
|
||||
"no-file-played-notification" : u"{} is not playing a file", # Username # TODO: Translate into Russian
|
||||
"notplaying-notification" : u"Люди, которые не смотрят ничего:",
|
||||
"userlist-room-notification" : u"В комнате '{}':", # Room
|
||||
"userlist-file-notification" : u"File", # TODO: Translate into Russian (Файл?)
|
||||
"controller-userlist-userflag" : u"Operator", # TODO: Translate into Russian (this is to indicate a user is a controller in the ConsoleUI userlist)
|
||||
"ready-userlist-userflag" : u"Ready", # TODO: Translate into Russian (this is to indicate a user is ready to watch in the ConsoleUI userlist)
|
||||
|
||||
"update-check-failed-notification" : u"Could not automatically check whether Syncplay {} is up to date. Want to visit http://syncplay.pl/ to manually check for updates?", #Syncplay version # TODO: Translate into Russian
|
||||
"syncplay-uptodate-notification" : u"Syncplay is up to date", # TODO: Translate into Russian
|
||||
"syncplay-updateavailable-notification" : u"A new version of Syncplay is available. Do you want to download it?", # TODO: Translate into Russian
|
||||
|
||||
"mplayer-file-required-notification" : u"Для использования Syncplay с mplayer необходимо передать файл в качестве параметра",
|
||||
"mplayer-file-required-notification/example" : u"Пример использования: syncplay [options] [url|path/]filename",
|
||||
@ -369,13 +418,15 @@ ru = {
|
||||
"commandlist-notification/pause" : u"\tp - вкл./выкл. паузу",
|
||||
"commandlist-notification/seek" : u"\t[s][+-]time - перемотать к заданному моменту времени, если не указан + или -, то время считается абсолютным (от начала файла) в секундах или мин:сек",
|
||||
"commandlist-notification/help" : u"\th - помощь",
|
||||
"commandlist-notification/create" : u"\tc [name] - create controlled room using name of current room", # TODO: Translate into Russian
|
||||
"commandlist-notification/auth" : u"\ta [password] - authenticate as room controller with controller password", # TODO: Translate into Russian
|
||||
"commandlist-notification/toggle" : u"\tt - toggles whether you are ready to watch or not", # TODO: Translate into Russian
|
||||
"commandlist-notification/create" : u"\tc [name] - create managed room using name of current room", # TODO: Translate into Russian
|
||||
"commandlist-notification/auth" : u"\ta [password] - authenticate as room operator with controller password", # TODO: Translate into Russian
|
||||
"syncplay-version-notification" : u"Версия Syncplay: {}", # syncplay.version
|
||||
"more-info-notification" : u"Больше информации на {}", # projectURL
|
||||
|
||||
"gui-data-cleared-notification" : u"Syncplay очистил путь и информацию о состоянии окна, использованного GUI.",
|
||||
"language-changed-msgbox-label" : u"Language will be changed when you run Syncplay.",
|
||||
"language-changed-msgbox-label" : u"Language will be changed when you run Syncplay.", # TODO: Translate into Russian
|
||||
"promptforupdate-label" : u"Is it okay for Syncplay to automatically check for updates from time to time?", # TODO: Translate into Russian
|
||||
|
||||
"vlc-version-mismatch" : u"Внимание: Вы используете VLC устаревшей версии {}. К сожалению, Syncplay способен работать с VLC {} и выше.", # VLC version, VLC min version
|
||||
"vlc-interface-version-mismatch" : u"Внимание: В используете модуль интерфейса Syncplay устаревшей версии {} для VLC. К сожалению, Syncplay способен работать с версией {} и выше.", # VLC interface version, VLC interface min version
|
||||
@ -416,6 +467,9 @@ ru = {
|
||||
"vlc-failed-versioncheck" : u"Данная версия VLC не поддерживается Syncplay. Пожалуйста, используйте VLC версии 2 или выше.",
|
||||
"vlc-failed-other" : u"Во время загрузки скрипта интерфейса syncplay.lua в VLC произошла следующая ошибка: {}", # Syncplay Error
|
||||
|
||||
"invalid-seek-value" : u"Invalid seek value", # TODO: Translate into Russian
|
||||
"invalid-offset-value" : u"Invalid offset value", # TODO: Translate into Russian
|
||||
|
||||
# Client arguments
|
||||
"argument-description" : u'Решение для синхронного воспроизведения в VLC, MPlayer или MPC-HC через Интернет.',
|
||||
"argument-epilog" : u'Если параметр не будет передан, то будет использоваться значение, указанное в _config.',
|
||||
@ -461,10 +515,12 @@ ru = {
|
||||
"privacy-dontsend-option" : u"не отпр.",
|
||||
"filename-privacy-label" : u"Имя файла:",
|
||||
"filesize-privacy-label" : u"Размер файла:",
|
||||
"checkforupdatesautomatically-label" : u"Проверять обновления автоматически", # TODO: Confirm Russian translation
|
||||
"slowondesync-label" : u"Замедлять при небольших рассинхронизациях (не поддерживаетя в MPC-HC)",
|
||||
"rewindondesync-label" : u"Перемотка при больших рассинхронизациях (настоятельно рекомендуется)",
|
||||
"dontslowdownwithme-label" : u"Никогда не замедлять или перематывать видео другим", # TODO: Update new wording into Russian (should state "Experimental" in brackets at the end)
|
||||
"pauseonleave-label" : u"Приостанавливать, когда кто-то уходит (например, отключился)",
|
||||
"readyatstart-label" : u"Set me as 'ready to watch' by default", # TODO: Translate into Russian
|
||||
"fastforwardondesync-label" : u"Fast-forward if lagging behind (recommended)", # TODO: Translate into Russian
|
||||
"forceguiprompt-label" : u"Не показывать больше этот диалог", # (Inverted)
|
||||
"nostore-label" : u"Не сохранять текущую конфигурацию", # (Inverted)
|
||||
@ -472,17 +528,19 @@ ru = {
|
||||
|
||||
"showosdwarnings-label" : u"Показывать предупреждения (напр., когда файлы не совпадают)",
|
||||
"showsameroomosd-label" : u"Показывать события Вашей комнаты",
|
||||
"shownoncontrollerosd-label" : "Include events from non-controllers in controlled rooms", # TODO: Translate into Russiann
|
||||
"shownoncontrollerosd-label" : u"Include events from non-operators in managed rooms", # TODO: Translate into Russiann
|
||||
"showdifferentroomosd-label" : u"Показывать события других комнат",
|
||||
"showslowdownosd-label" : u"Показывать уведомления о замедлении/перемотке",
|
||||
"showcontactinfo-label" : u"Отображать контактную информацию разработчиков",
|
||||
"language-label" : u"Language", # TODO: Translate into Russian
|
||||
"automatic-language" : "Automatic ({})", # Automatic language # TODO: Translate into Russian
|
||||
"language-label" : u"Language:", # TODO: Translate into Russian
|
||||
"automatic-language" : u"Default ({})", # Automatic language # TODO: Translate into Russian
|
||||
"showdurationnotification-label" : u"Предупреждать о несовпадении продолжительности видео",
|
||||
"basics-label" : u"Основное",
|
||||
"misc-label" : u"Misc", # TODO: Translate into Russian
|
||||
"core-behaviour-title" : "Core room behaviour", # TODO: Translate into Russian
|
||||
"syncplay-internals-title" : u"Syncplay internals", # TODO: Translate into Russian
|
||||
"sync-label" : u"Синхронизация",
|
||||
"sync-lagging-title" : u"If others are lagging behind...", # TODO: Translate into Russian
|
||||
"sync-other-title" : u"Other sync options", # TODO: Translate into Russian
|
||||
"sync-otherslagging-title" : u"If others are lagging behind...", # TODO: Translate into Russian
|
||||
"sync-youlaggging-title" : u"If you are lagging behind...", # TODO: Translate into Russian
|
||||
"messages-label" : u"Сообщения",
|
||||
"messages-osd-title" : u"On-screen Display settings", # TODO: Translate into Russian
|
||||
"messages-other-title" : u"Other display settings", # TODO: Translate into Russian
|
||||
@ -496,46 +554,56 @@ ru = {
|
||||
|
||||
"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/new\">задавайте вопросы через GitHub</a>. Кроме того, заходите на <a href=\"http://syncplay.pl/\">http://syncplay.pl/</a> за инорфмацией, помощью и обновлениями!",
|
||||
|
||||
"joinroom-guibuttonlabel" : u"Зайти в комнату",
|
||||
"seektime-guibuttonlabel" : u"Перемотать",
|
||||
"undoseek-guibuttonlabel" : u"Отменить перемотку",
|
||||
"togglepause-guibuttonlabel" : u"Вкл./выкл. паузу",
|
||||
"play-guibuttonlabel" : u"Play",
|
||||
"pause-guibuttonlabel" : u"Пауза",
|
||||
"joinroom-menu-label" : u"Зайти в комнату",
|
||||
"seektime-menu-label" : u"Перемотать",
|
||||
"undoseek-menu-label" : u"Отменить перемотку",
|
||||
"play-menu-label" : u"Play",
|
||||
"pause-menu-label" : u"Пауза",
|
||||
"playbackbuttons-menu-label" : u"Show playback buttons", # TODO: Translate into Russian
|
||||
"autoplay-menu-label" : u"Show auto-play button", # TODO: Translate into Russian
|
||||
"autoplay-guipushbuttonlabel" : u"Auto-play when everyone is ready", # TODO: Translate into Russian
|
||||
|
||||
|
||||
"ready-guipushbuttonlabel" : u"I'm ready to watch!", # TODO: Translate into Russian
|
||||
|
||||
"roomuser-heading-label" : u"Комната / Пользователь",
|
||||
"size-heading-label" : "Size", # TODO: Translate into Russian
|
||||
"duration-heading-label" : "Length", # TODO: Translate into Russian
|
||||
"filename-heading-label" : "Filename", # TODO: Translate into Russian
|
||||
"size-heading-label" : u"Size", # TODO: Translate into Russian
|
||||
"duration-heading-label" : u"Length", # TODO: Translate into Russian
|
||||
"filename-heading-label" : u"Filename", # TODO: Translate into Russian
|
||||
"notifications-heading-label" : u"Уведомления",
|
||||
"userlist-heading-label" : u"Кто что смотрит",
|
||||
"othercommands-heading-label" : u"Другие команды",
|
||||
"room-heading-label" : u"Комната",
|
||||
"seek-heading-label" : u"Перемотка",
|
||||
|
||||
"browseformedia-label" : u"Выбрать видеофайл",
|
||||
|
||||
"file-menu-label" : u"&Файл", # & precedes shortcut key
|
||||
"openmedia-menu-label" : u"&Открыть видеофайл",
|
||||
"openstreamurl-menu-label" : u"Open &media stream URL", # TODO: Translate into Russian
|
||||
"exit-menu-label" : u"&Выход",
|
||||
"advanced-menu-label" : u"&Дополнительно",
|
||||
"window-menu-label" : u"&Window", # TODO: Translate into Russian
|
||||
"setoffset-menu-label" : u"Установить &смещение",
|
||||
"createcontrolledroom-menu-label" : u"&Create controlled room", # TODO: Translate into Russianv
|
||||
"identifyascontroller-menu-label" : u"&Identify as room controller", # TODO: Translate into Russian
|
||||
"createcontrolledroom-menu-label" : u"&Create managed room", # TODO: Translate into Russian
|
||||
"identifyascontroller-menu-label" : u"&Identify as room operator", # TODO: Translate into Russian
|
||||
|
||||
"playback-menu-label" : u"&Playback", # TODO: Translate into Russian
|
||||
|
||||
"help-menu-label" : u"&Помощь",
|
||||
"userguide-menu-label" : u"&Руководство Пользователя",
|
||||
"update-menu-label" : u"Check for &update", # TODO: Translate into Russian
|
||||
|
||||
"setoffset-msgbox-label" : u"Установить смещение",
|
||||
"offsetinfo-msgbox-label" : u"Смещение (см. как использовать на http://syncplay.pl/guide/):",
|
||||
|
||||
"createcontrolledroom-msgbox-label" : u"Create controlled room", # TODO: Translate into Russian
|
||||
"controlledroominfo-msgbox-label" : u"Enter name of controlled room\r\n(see http://syncplay.pl/guide/ for usage instructions):", # TODO: Translate into Russian
|
||||
"promptforstreamurl-msgbox-label" : u"Open media stream URL", # TODO: Translate into Russian
|
||||
"promptforstreamurlinfo-msgbox-label" : u"Stream URL", # TODO: Translate into Russian
|
||||
|
||||
"identifyascontroller-msgbox-label" : u"Identify as Room Controller", # TODO: Translate into Russian
|
||||
"createcontrolledroom-msgbox-label" : u"Create managed room", # TODO: Translate into Russian
|
||||
"controlledroominfo-msgbox-label" : u"Enter name of managed room\r\n(see http://syncplay.pl/guide/ for usage instructions):", # TODO: Translate into Russian
|
||||
|
||||
"identifyascontroller-msgbox-label" : u"Identify as room operator", # TODO: Translate into Russian
|
||||
"identifyinfo-msgbox-label" : u"Enter controller password for this room\r\n(see http://syncplay.pl/guide/ for usage instructions):", # TODO: Translate into Russian
|
||||
|
||||
"megabyte-suffix" : " MB", # Technically it is a mebibyte # TODO: Translate into Russian
|
||||
"megabyte-suffix" : u" MB", # Technically it is a mebibyte # TODO: Translate into Russian
|
||||
|
||||
# Tooltips
|
||||
|
||||
@ -550,38 +618,35 @@ ru = {
|
||||
"more-tooltip" : u"Показать дополнительные настройки.",
|
||||
"slowdown-threshold-tooltip" : u"Отставание самого медленного клиента, необходимое для временного уменьшения скорости видео (по умолчанию: {} сек.).".format(constants.DEFAULT_SLOWDOWN_KICKIN_THRESHOLD),
|
||||
"rewind-threshold-tooltip" : u"Отставание самого медленного клиента, необходимое для перемотки назад в целях синхронизации (по умолчанию: {} сек.).".format(constants.DEFAULT_REWIND_THRESHOLD),
|
||||
"fastforward-threshold-tooltip" : u"Time behind room controller before seeking to get back in sync (default: {} secs).".format(constants.DEFAULT_FASTFORWARD_THRESHOLD), # TODO: Translate into Russian
|
||||
"fastforward-threshold-tooltip" : u"Time behind room operator before seeking to get back in sync (default: {} secs).".format(constants.DEFAULT_FASTFORWARD_THRESHOLD), # TODO: Translate into Russian
|
||||
"filename-privacy-tooltip" : u"Режим приватности для передачи имени воспроизводимого файла на сервер.",
|
||||
"filesize-privacy-tooltip" : u"Режим приватности для передачи размера воспроизводимого файла на сервер.",
|
||||
"privacy-sendraw-tooltip" : u"Отправляет эту информацию без шифрования. Рекомендуемая опция с наибольшей функциональностью.",
|
||||
"privacy-sendhashed-tooltip" : u"Отправляет хэш-сумму этой информации, делая ее невидимой для других пользователей.",
|
||||
"privacy-dontsend-tooltip" : u"Не отправлять эту информацию на сервер. Предоставляет наибольшую приватность.",
|
||||
"checkforupdatesautomatically-tooltip" : u"Regularly check with the Syncplay website to see whether a new version of Syncplay is available.", # TODO: Translate into Russian
|
||||
"slowondesync-tooltip" : u"Временно уменьшить скорость воспроизведения в целях синхронизации с другими зрителями. Не поддерживается в MPC-HC.",
|
||||
"dontslowdownwithme-tooltip" : u"Ваши лаги не будут влиять на других зрителей.",
|
||||
"pauseonleave-tooltip" : u"Приостановить воспроизведение, если Вы покинули комнату или кто-то из зрителей отключился от сервера.",
|
||||
"readyatstart-tooltip" : u"Set yourself as 'ready' at start (otherwise you are set as 'not ready' until you change your readiness state)", # TODO: Translate into Russian
|
||||
"forceguiprompt-tooltip" : u"Окно настройки не будет отображаться при открытии файла в Syncplay.", # (Inverted)
|
||||
"nostore-tooltip" : u"Запустить Syncplay с данной конфигурацией, но не сохранять изменения навсегда.", # (Inverted)
|
||||
"rewindondesync-tooltip" : u"Перематывать назад, когда это необходимо для синхронизации. Отключение этой опции может привести к большим рассинхронизациям!",
|
||||
"fastforwardondesync-tooltip" : u"Jump forward when out of sync with room controller (or your pretend position if 'Never slow down or rewind others' enabled).", # TODO: Translate into Russian
|
||||
"fastforwardondesync-tooltip" : u"Jump forward when out of sync with room operator (or your pretend position if 'Never slow down or rewind others' enabled).", # TODO: Translate into Russian
|
||||
"showosd-tooltip" : u"Отправлять сообщения Syncplay в видеопроигрыватель и отображать их поверх видео (OSD - On Screen Display).",
|
||||
"showosdwarnings-tooltip" : u"Показывать OSC-предупреждения, если проигрываются разные файлы или если Вы в комнате больше никого нет.",
|
||||
"showsameroomosd-tooltip" : u"Показывать OSD-уведомления о событиях, относящихся к комнате, в которой Вы находитесь.",
|
||||
"shownoncontrollerosd-tooltip" : u"Show OSD notifications for events relating to non-controllers who are in controllerd rooms.", # TODO: Translate into Russian
|
||||
"shownoncontrollerosd-tooltip" : u"Show OSD notifications for events relating to non-operators who are in controllerd rooms.", # TODO: Translate into Russian
|
||||
"showdifferentroomosd-tooltip" : u"Показывать OSD-уведомления о событиях, относящихся к любым другим комнатам.",
|
||||
"showslowdownosd-tooltip" : u"Показывать уведомления о замедлении или перемотке в целях синхронизации.",
|
||||
"showcontactinfo-tooltip" : u"Показывать информационных блок с контактной информацией разработчиков Syncplay на главном окне Syncplay.",
|
||||
"showdurationnotification-tooltip" : u"Полезно, когда сегмент составного файла отсутствует. Возможны ложные срабатывания.",
|
||||
"language-tooltip" : u"Language to be used by Syncplay.", # TODO: Translate into Russian
|
||||
|
||||
"help-tooltip" : u"Открыть Руководство Пользователя на Syncplay.pl.",
|
||||
"reset-tooltip" : u"Сбрасывает все настройки Syncplay в начальное состояние.",
|
||||
|
||||
"togglepause-tooltip" : u"Приостановить/продолжить просмотр.",
|
||||
"play-tooltip" : u"Продолжить просмотр.",
|
||||
"pause-tooltip" : u"Приостановить просмотр.",
|
||||
"undoseek-tooltip" : u"Перейти к тому месту, которое Вы просматривали до перемотки.",
|
||||
"joinroom-tooltip" : u"Покинуть комнату и зайти в другую, указанную комнату.",
|
||||
"seektime-tooltip" : u"Перемотать к определенному моменту времени (указывать в секундах или мин:сек). Используйте +/-, чтобы перемотать вперед/назад относительно настоящего момента.",
|
||||
"seektime-msgbox-label" : u"Перемотать к определенному моменту времени (указывать в секундах или мин:сек). Используйте +/-, чтобы перемотать вперед/назад относительно настоящего момента.",
|
||||
|
||||
# In-userlist notes (GUI)
|
||||
"differentsize-note" : u"Размер файла не совпадает!",
|
||||
@ -604,7 +669,8 @@ ru = {
|
||||
"server-port-argument" : u'номер TCP порта сервера',
|
||||
"server-password-argument" : u'пароль к серверу',
|
||||
"server-isolate-room-argument" : u'должны ли комнаты быть изолированными?',
|
||||
"server-salt-argument" : u"random string used to generate controlled room passwords", # TODO: Translate into Russian (note: as you may already be aware, 'salt' means Соль (криптография))
|
||||
"server-salt-argument" : u"random string used to generate managed room passwords", # TODO: Translate into Russian (note: as you may already be aware, 'salt' means Соль (криптография))
|
||||
"server-disable-ready-argument" : u"disable readiness feature", # TODO: Translate into Russian
|
||||
"server-motd-argument" : u"путь к файлу, из которого будет извлекаться MOTD-сообщение",
|
||||
"server-messed-up-motd-unescaped-placeholders" : u"MOTD-сообщение содержит неэкранированные спец.символы. Все знаки $ должны быть продублированы ($$).",
|
||||
"server-messed-up-motd-too-long" : u"MOTD-сообщение слишком длинное: максимальная длина - {} символ(ов), текущая длина - {} символ(ов).",
|
||||
@ -652,19 +718,36 @@ de = {
|
||||
"playing-notification" : u"<{}> spielt '{}' ({})", # User, file, duration
|
||||
"playing-notification/room-addendum" : u" in Raum: '{}'", # Room
|
||||
|
||||
"identifying-as-controller-notification" : u"Identifiziere als Raumleiter mit Passwort '{}'...", # TODO: find a better translation to "room controller"
|
||||
"not-all-ready" : u"Not ready: {}", # Usernames # TODO: Translate into German
|
||||
"all-users-ready" : u"Everyone is ready ({} users)", #Number of ready users # TODO: Translate into German
|
||||
"ready-to-unpause-notification" : u"You are now set as ready - unpause again to unpause", # TODO: Translate into German
|
||||
|
||||
"identifying-as-controller-notification" : u"Identifiziere als Raumleiter mit Passwort '{}'...", # TODO: find a better translation to "room operator"
|
||||
"failed-to-identify-as-controller-notification" : u"<{}> konnte sich nicht als Raumleiter identifizieren.",
|
||||
"authenticated-as-controller-notification" : u"<{}> authentifizierte sich als Raumleiter",
|
||||
"created-controlled-room-notification" : u"Created managed room '{}' with password '{}'. Please save this information for future reference!", # RoomName, controlPassword # TODO: Translate into German
|
||||
|
||||
"file-different-notification" : u"Deine Datei scheint sich von <{}>s zu unterscheiden", # User
|
||||
"file-differences-notification" : u"Deine Datei unterscheidet sich auf folgende Art: ",
|
||||
"room-files-not-same" : u"Nicht alle Dateien im Raum sind gleich",
|
||||
"file-differences-notification" : u"Deine Datei unterscheidet sich auf folgende Art: {}",
|
||||
"room-file-differences" : u"File differences: {}", # File differences (filename, size, and/or duration) # TODO: Translate into German
|
||||
"file-difference-filename" : u"name", # TODO: Translate into German
|
||||
"file-difference-filesize" : u"size", # TODO: Translate into German
|
||||
"file-difference-duration" : u"duration", # TODO: Translate into German
|
||||
"alone-in-the-room": u"Du bist alleine im Raum",
|
||||
|
||||
"different-filesize-notification" : u" (ihre Dateigröße ist anders als deine!)",
|
||||
"userlist-playing-notification" : u"{} is playing:", #Username # TODO: Translate into German (same as playing-notification?)
|
||||
"file-played-by-notification" : u"Datei: {} wird gespielt von:", # File
|
||||
"no-file-played-notification" : u"{} is not playing a file", # Username # TODO: Translate into German
|
||||
"notplaying-notification" : u"Personen im Raum, die keine Dateien spielen:",
|
||||
"userlist-room-notification" : u"In Raum '{}':", # Room
|
||||
"userlist-file-notification" : u"File", # TODO: Translate into German (Datei?)
|
||||
"controller-userlist-userflag" : u"Operator", # TODO: Translate into German (this is to indicate a user is a room operator in the ConsoleUI userlist)
|
||||
"ready-userlist-userflag" : u"Ready", # TODO: Translate into German (this is to indicate a user is ready to watch in the ConsoleUI userlist)
|
||||
|
||||
"update-check-failed-notification" : u"Could not automatically check whether Syncplay {} is up to date. Want to visit http://syncplay.pl/ to manually check for updates?", #Syncplay version # TODO: Translate into German
|
||||
"syncplay-uptodate-notification" : u"Syncplay is up to date", # TODO: Translate into German
|
||||
"syncplay-updateavailable-notification" : u"A new version of Syncplay is available. Do you want to download it?", # TODO: Translate into German
|
||||
|
||||
"mplayer-file-required-notification" : u"Syncplay für mplayer benötigt eine Datei-Angabe beim Start",
|
||||
"mplayer-file-required-notification/example" : u"Anwendungsbeispiel: syncplay [optionen] [url|pfad/]Dateiname",
|
||||
@ -678,6 +761,7 @@ de = {
|
||||
"commandlist-notification/pause" : u"\tp - Pausieren / weiter",
|
||||
"commandlist-notification/seek" : u"\t[s][+-]Zeit - zu einer bestimmten Zeit spulen, ohne + oder - wird als absolute Zeit gewertet; Angabe in Sekunden oder Minuten:Sekunden",
|
||||
"commandlist-notification/help" : u"\th - Diese Hilfe",
|
||||
"commandlist-notification/toggle" : u"\tt - toggles whether you are ready to watch or not", # TODO: Translate into German
|
||||
"commandlist-notification/create" : u"\tc [name] - erstelle zentral gesteuerten Raum mit dem aktuellen Raumnamen",
|
||||
"commandlist-notification/auth" : u"\ta [password] - authentifiziere als Raumleiter mit Passwort",
|
||||
"syncplay-version-notification" : u"Syncplay Version: {}", # syncplay.version
|
||||
@ -685,6 +769,7 @@ de = {
|
||||
|
||||
"gui-data-cleared-notification" : u"Syncplay hat die Pfad und Fensterdaten der Syncplay-GUI zurückgesetzt.",
|
||||
"language-changed-msgbox-label" : u"Die Sprache wird geändert, wenn du Syncplay neu startest.",
|
||||
"promptforupdate-label" : u"Is it okay for Syncplay to automatically check for updates from time to time?", # TODO: Translate into German
|
||||
|
||||
"vlc-version-mismatch": u"Warnung: Du nutzt VLC Version {}, aber Syncplay wurde für VLC ab Version {} entwickelt.", # VLC version, VLC min version
|
||||
"vlc-interface-version-mismatch": u"Warnung: Du nutzt Version {} des VLC-Syncplay Interface-Moduls, Syncplay benötigt aber mindestens Version {}.", # VLC interface version, VLC interface min version
|
||||
@ -699,7 +784,7 @@ de = {
|
||||
"server-timeout-error" : u"Timeout: Verbindung zum Server fehlgeschlagen",
|
||||
"mpc-slave-error" : u"Kann MPC nicht im Slave-Modus starten!",
|
||||
"mpc-version-insufficient-error" : u"MPC-Version nicht ausreichend, bitte nutze `mpc-hc` >= `{}`",
|
||||
"mpv-version-error" : "Syncplay ist nicht kompatibel mit dieser Version von mpv. Bitte benutze eine andere Version (z.B. Git HEAD).",
|
||||
"mpv-version-error" : u"Syncplay ist nicht kompatibel mit dieser Version von mpv. Bitte benutze eine andere Version (z.B. Git HEAD).",
|
||||
"player-file-open-error" : u"Fehler beim Öffnen der Datei durch den Player",
|
||||
"player-path-error" : u"Ungültiger Player-Pfad",
|
||||
"hostname-empty-error" : u"Hostname darf nicht leer sein",
|
||||
@ -725,6 +810,9 @@ de = {
|
||||
"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
|
||||
|
||||
"invalid-seek-value" : u"Invalid seek value", # TODO: Translate into German
|
||||
"invalid-offset-value" : u"Invalid offset value", # TODO: Translate into German
|
||||
|
||||
# Client arguments
|
||||
"argument-description" : u'Anwendung, um mehrere MPlayer, MPC-HC und VLC-Instanzen über das Internet zu synchronisieren.',
|
||||
"argument-epilog" : u'Wenn keine Optionen angegeben sind, werden die _config-Werte verwendet',
|
||||
@ -770,9 +858,11 @@ de = {
|
||||
"privacy-dontsend-option" : u"Nicht senden",
|
||||
"filename-privacy-label" : u"Dateiname:",
|
||||
"filesize-privacy-label" : u"Dateigröße:",
|
||||
"checkforupdatesautomatically-label" : u"Automatisch nach Updates suche", # TODO: Confirm German translation
|
||||
"slowondesync-label" : u"Verlangsamen wenn nicht synchron (nicht unterstützt mit MPC-HC)",
|
||||
"dontslowdownwithme-label" : u"Nie verlangsamen oder andere zurückspulen (Experimentell)",
|
||||
"pauseonleave-label" : u"Pausieren wenn ein Benutzer austritt",
|
||||
"readyatstart-label" : u"Set me as 'ready to watch' by default", # TODO: Translate into German
|
||||
"forceguiprompt-label" : u"Diesen Dialog nicht mehr anzeigen",
|
||||
"nostore-label" : u"Diese Konfiguration nicht speichern",
|
||||
"showosd-label" : u"OSD-Nachrichten anzeigen",
|
||||
@ -782,14 +872,16 @@ de = {
|
||||
"shownoncontrollerosd-label" : u"Zeige Ereignisse von nicht geführten Räumen in geführten Räumen.",
|
||||
"showdifferentroomosd-label" : u"Zeige Ereignisse in anderen Räumen",
|
||||
"showslowdownosd-label" : u"Zeige Verlangsamungs/Zurücksetzungs-Benachrichtigung",
|
||||
"showcontactinfo-label" : u"Zeige Kontaktinformationen",
|
||||
"language-label" : u"Sprache",
|
||||
"automatic-language" : "Automatisch ({})", # Automatic language
|
||||
"language-label" : u"Sprache:",
|
||||
"automatic-language" : u"Automatisch ({})", # Default language # TODO: Change to German translation of "default"
|
||||
"showdurationnotification-label" : u"Zeige Warnung wegen unterschiedlicher Dauer",
|
||||
"basics-label" : u"Basics",
|
||||
"misc-label" : u"Misc", # TODO: Translate into German
|
||||
"core-behaviour-title" : u"Core room behaviour", # TODO: Translate into German
|
||||
"syncplay-internals-title" : u"Syncplay internals", # TODO: Translate into German
|
||||
"sync-label" : u"Synchronisation",
|
||||
"sync-lagging-title" : u"Wenn andere laggen...",
|
||||
"sync-other-title" : u"Weitere Synchronisationsoptionen",
|
||||
"sync-otherslagging-title" : u"Wenn andere laggen...",
|
||||
"sync-youlaggging-title" : u"If you are lagging behind...", # TODO: Translate into German
|
||||
"messages-label" : u"Nachrichten",
|
||||
"messages-osd-title" : u"OSD-(OnScreenDisplay)-Einstellungen",
|
||||
"messages-other-title" : u"Weitere Display-Einstellungen",
|
||||
@ -803,12 +895,16 @@ de = {
|
||||
|
||||
"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/new\">ö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.",
|
||||
|
||||
"joinroom-guibuttonlabel" : u"Raum beitreten",
|
||||
"seektime-guibuttonlabel" : u"Spule zu Zeit",
|
||||
"undoseek-guibuttonlabel" : u"Rückgängig",
|
||||
"togglepause-guibuttonlabel" : u"Pause umschalten",
|
||||
"play-guibuttonlabel" : u"Wiedergabe",
|
||||
"pause-guibuttonlabel" : u"Pause",
|
||||
"joinroom-menu-label" : u"Raum beitreten",
|
||||
"seektime-menu-label" : u"Spule zu Zeit",
|
||||
"undoseek-menu-label" : u"Rückgängig",
|
||||
"play-menu-label" : u"Wiedergabe",
|
||||
"pause-menu-label" : u"Pause",
|
||||
"playbackbuttons-menu-label" : u"Show playback buttons", # TODO: Translate into German
|
||||
"autoplay-menu-label" : u"Show auto-play button", # TODO: Translate into German
|
||||
"autoplay-guipushbuttonlabel" : u"Auto-play when everyone is ready", # TODO: Translate into German
|
||||
|
||||
"ready-guipushbuttonlabel" : u"I'm ready to watch!", # TODO: Translate into German
|
||||
|
||||
"roomuser-heading-label" : u"Raum / Benutzer",
|
||||
"size-heading-label" : u"Größe",
|
||||
@ -816,26 +912,30 @@ de = {
|
||||
"filename-heading-label" : u"Dateiname",
|
||||
"notifications-heading-label" : u"Benachrichtigungen",
|
||||
"userlist-heading-label" : u"Liste der gespielten Dateien",
|
||||
"othercommands-heading-label" : u"Andere Befehle",
|
||||
"room-heading-label" : u"Raum",
|
||||
"seek-heading-label" : u"Spulen",
|
||||
|
||||
"browseformedia-label" : u"Nach Mediendateien durchsuchen",
|
||||
|
||||
"file-menu-label" : u"&Datei", # & precedes shortcut key
|
||||
"openmedia-menu-label" : u"&Mediendatei öffnen...",
|
||||
"openstreamurl-menu-label" : u"Open &media stream URL", # TODO: Translate into German
|
||||
"exit-menu-label" : u"&Beenden",
|
||||
"advanced-menu-label" : u"&Erweitert",
|
||||
"window-menu-label" : u"&Window", # TODO: Translate into German
|
||||
"setoffset-menu-label" : u"&Offset einstellen",
|
||||
"createcontrolledroom-menu-label" : u"&Zentral gesteuerten Raum erstellen",
|
||||
"identifyascontroller-menu-label" : u"Als Raumleiter &identifizieren",
|
||||
|
||||
"playback-menu-label" : u"&Playback", # TODO: Translate into German
|
||||
|
||||
"help-menu-label" : u"&Hilfe",
|
||||
"userguide-menu-label" : u"&Benutzerhandbuch öffnen",
|
||||
"update-menu-label" : u"Check for &update", # TODO: Translate into German
|
||||
|
||||
"setoffset-msgbox-label" : u"Offset einstellen",
|
||||
"offsetinfo-msgbox-label" : u"Offset (siehe http://syncplay.pl/guide/ für eine Anleitung [Englisch]):",
|
||||
|
||||
"promptforstreamurl-msgbox-label" : u"Open media stream URL", # TODO: Translate into German
|
||||
"promptforstreamurlinfo-msgbox-label" : u"Stream URL", # TODO: Translate into German
|
||||
|
||||
"createcontrolledroom-msgbox-label" : u"Zentral gesteuerten Raum erstellen",
|
||||
"controlledroominfo-msgbox-label" : u"Namen des zentral gesteuerten Raums eingeben\r\n(siehe http://syncplay.pl/guide/ für eine Anleitung [Englisch]):",
|
||||
@ -864,11 +964,13 @@ de = {
|
||||
"privacy-sendraw-tooltip" : u"Die Information im Klartext übertragen. Dies ist die Standard-Einstellung mit der besten Funktionalität.",
|
||||
"privacy-sendhashed-tooltip" : u"Die Informationen gehasht übertragen, um sie für andere Clients schwerer lesbar zu machen.",
|
||||
"privacy-dontsend-tooltip" : u"Diese Information nicht übertragen. Dies garantiert den größtmöglichen Datanschutz.",
|
||||
"checkforupdatesautomatically-tooltip" : u"Regularly check with the Syncplay website to see whether a new version of Syncplay is available.", # TODO: Translate into German
|
||||
"slowondesync-tooltip" : u"Reduziert die Abspielgeschwindigkeit zeitweise, um die Synchronität zu den anderen Clients wiederherzustellen.",
|
||||
"rewindondesync-label" : u"Zurückspulen bei großer Zeitdifferenz (empfohlen)",
|
||||
"fastforwardondesync-label" : u"Vorspulen wenn das Video lagt (empfohlen)",
|
||||
"dontslowdownwithme-tooltip" : u"Lässt andere nicht langsamer werden oder zurückspringen, wenn deine Wiedergabe hängt.",
|
||||
"pauseonleave-tooltip" : u"Wiedergabe anhalten, wenn deine Verbindung verloren geht oder jemand den Raum verlässt.",
|
||||
"readyatstart-tooltip" : u"Set yourself as 'ready' at start (otherwise you are set as 'not ready' until you change your readiness state)", #TODO: Translate into German
|
||||
"forceguiprompt-tooltip" : u"Der Konfigurationsdialog wird nicht angezeigt, wenn eine Datei mit Syncplay geöffnet wird.",
|
||||
"nostore-tooltip" : u"Syncplay mit den angegebenen Einstellungen starten, diese aber nicht dauerhaft speichern.",
|
||||
"rewindondesync-tooltip" : u"Zum Wiederherstellen der Synchronität in der Zeit zurückspringen (empfohlen)",
|
||||
@ -879,19 +981,14 @@ de = {
|
||||
"shownoncontrollerosd-tooltip" : u"OSD-Meldungen bei Ereignissen verursacht durch nicht-Raumleiter in zentral gesteuerten Räumen anzeigen.",
|
||||
"showdifferentroomosd-tooltip" : u"OSD-Meldungen zu anderen Räumen als dem aktuell betretenen anzeigen.",
|
||||
"showslowdownosd-tooltip" : u"Meldungen bei Geschwindigkeitsänderung anzeigen.",
|
||||
"showcontactinfo-tooltip" : u"Kontaktinformationen zu den Syncplay-Entwicklern im Hauptfenster anzeigen.",
|
||||
"showdurationnotification-tooltip" : u"Nützlich, wenn z.B. ein Teil eines mehrteiligen Videos fehlt, kann jedoch auch fehlerhaft anschlagen.",
|
||||
"language-tooltip" : u"Die verwendete Sprache von Syncplay",
|
||||
|
||||
"help-tooltip" : u"Öffnet Hilfe auf syncplay.pl [Englisch]",
|
||||
"reset-tooltip" : u"Alle Einstellungen auf Standardwerte zurücksetzen.",
|
||||
|
||||
"togglepause-tooltip" : u"Datei starten/pausieren",
|
||||
"play-tooltip" : u"Fortsetzen",
|
||||
"pause-tooltip" : u"Pausieren",
|
||||
"undoseek-tooltip" : u"Den letzten Spulvorgang rückgängig machen.",
|
||||
"joinroom-tooltip" : u"Den aktuellen Raum verlassen und stattdessen den angegebenen betreten.",
|
||||
"seektime-tooltip" : u"Springe zur angegebenen Zeit (in Sekunden oder min:sek). Verwende +/- zum relativen Springen.",
|
||||
"seektime-msgbox-label" : u"Springe zur angegebenen Zeit (in Sekunden oder min:sek). Verwende +/- zum relativen Springen.",
|
||||
|
||||
# In-userlist notes (GUI)
|
||||
"differentsize-note" : u"Verschiedene Größe!",
|
||||
@ -906,7 +1003,7 @@ de = {
|
||||
"welcome-server-notification" : u"Willkommen zum Syncplay-Server, v. {0}", # version
|
||||
"client-connected-room-server-notification" : u"{0}({2}) hat den Raum '{1}' betreten", # username, host, room
|
||||
"client-left-server-notification" : u"{0} hat den Server verlassen", # name
|
||||
"no-salt-notification" : "WICHTIGER HINWEIS: Damit von dem Server generierte Passwörter für geführte Räume auch nach einem Serverneustart funktionieren, starte den Server mit dem folgenden Parameter: --salt {}", #Salt
|
||||
"no-salt-notification" : u"WICHTIGER HINWEIS: Damit von dem Server generierte Passwörter für geführte Räume auch nach einem Serverneustart funktionieren, starte den Server mit dem folgenden Parameter: --salt {}", #Salt
|
||||
|
||||
# Server arguments
|
||||
"server-argument-description" : u'Anwendung, um mehrere MPlayer, MPC-HC und VLC-Instanzen über das Internet zu synchronisieren. Server',
|
||||
@ -915,6 +1012,7 @@ de = {
|
||||
"server-password-argument" : u'Server Passwort',
|
||||
"server-isolate-room-argument" : u'Sollen die Räume isoliert sein?',
|
||||
"server-salt-argument" : u"zufällige Zeichenkette, die zur Erstellung von Passwörtern verwendet wird",
|
||||
"server-disable-ready-argument" : u"disable readiness feature", # TODO: Translate into German
|
||||
"server-motd-argument": u"Pfad zur Datei, von der die Nachricht des Tages geladen wird",
|
||||
"server-messed-up-motd-unescaped-placeholders": u"Die Nachricht des Tages hat unmaskierte Platzhalter. Alle $-Zeichen sollten verdoppelt werden ($$).",
|
||||
"server-messed-up-motd-too-long": u"Die Nachricht des Tages ist zu lang - Maximal {} Zeichen, aktuell {}.",
|
||||
@ -973,9 +1071,6 @@ def isValidLanguage(language):
|
||||
return messages.has_key(language)
|
||||
|
||||
def getMessage(type_, locale=None):
|
||||
if constants.SHOW_BUTTON_LABELS == False:
|
||||
if "-guibuttonlabel" in type_:
|
||||
return ""
|
||||
if constants.SHOW_TOOLTIPS == False:
|
||||
if "-tooltip" in type_:
|
||||
return ""
|
||||
|
||||
@ -306,7 +306,9 @@ class MpcHcApi:
|
||||
|
||||
class MPCHCAPIPlayer(BasePlayer):
|
||||
speedSupported = False
|
||||
secondaryOSDSupported = False
|
||||
customOpenDialog = False
|
||||
osdMessageSeparator = "; "
|
||||
|
||||
def __init__(self, client):
|
||||
from twisted.internet import reactor
|
||||
@ -393,7 +395,7 @@ class MPCHCAPIPlayer(BasePlayer):
|
||||
def openFile(self, filePath, resetPosition=False):
|
||||
self._mpcApi.openFile(filePath)
|
||||
|
||||
def displayMessage(self, message, duration = (constants.OSD_DURATION*1000)):
|
||||
def displayMessage(self, message, duration = (constants.OSD_DURATION*1000), secondaryOSD=False):
|
||||
self._mpcApi.sendOsd(message, constants.MPC_OSD_POSITION, duration)
|
||||
|
||||
@retry(MpcHcApi.PlayerNotReadyException, constants.MPC_MAX_RETRIES, constants.MPC_RETRY_WAIT_TIME, 1)
|
||||
|
||||
@ -10,6 +10,9 @@ import os
|
||||
class MplayerPlayer(BasePlayer):
|
||||
speedSupported = True
|
||||
customOpenDialog = False
|
||||
secondaryOSDSupported = False
|
||||
osdMessageSeparator = "\\n"
|
||||
|
||||
RE_ANSWER = re.compile(constants.MPLAYER_ANSWER_REGEX)
|
||||
POSITION_QUERY = 'time_pos'
|
||||
OSD_QUERY = 'osd_show_text'
|
||||
@ -83,7 +86,7 @@ class MplayerPlayer(BasePlayer):
|
||||
def _getProperty(self, property_):
|
||||
self._listener.sendLine("get_property {}".format(property_))
|
||||
|
||||
def displayMessage(self, message, duration=(constants.OSD_DURATION * 1000)):
|
||||
def displayMessage(self, message, duration=(constants.OSD_DURATION * 1000), secondaryOSD=False):
|
||||
self._listener.sendLine(u'{} "{!s}" {} {}'.format(self.OSD_QUERY, message, duration, constants.MPLAYER_OSD_LEVEL).encode('utf-8'))
|
||||
|
||||
def setSpeed(self, value):
|
||||
|
||||
@ -14,6 +14,9 @@ from syncplay.messages import getMessage
|
||||
class VlcPlayer(BasePlayer):
|
||||
speedSupported = True
|
||||
customOpenDialog = False
|
||||
secondaryOSDSupported = True
|
||||
osdMessageSeparator = "; "
|
||||
|
||||
RE_ANSWER = re.compile(constants.VLC_ANSWER_REGEX)
|
||||
SLAVE_ARGS = constants.VLC_SLAVE_ARGS
|
||||
if not sys.platform.startswith('darwin'):
|
||||
@ -83,16 +86,19 @@ class VlcPlayer(BasePlayer):
|
||||
self._positionAsk.clear()
|
||||
self._pausedAsk.clear()
|
||||
self._listener.sendLine(".")
|
||||
if not self._filechanged:
|
||||
if self._filename and not self._filechanged:
|
||||
self._positionAsk.wait()
|
||||
self._pausedAsk.wait()
|
||||
self._client.updatePlayerStatus(self._paused, self._position)
|
||||
else:
|
||||
self._client.updatePlayerStatus(self._client.getGlobalPaused(), self._client.getGlobalPosition())
|
||||
|
||||
def displayMessage(self, message, duration=constants.OSD_DURATION * 1000):
|
||||
def displayMessage(self, message, duration=constants.OSD_DURATION * 1000, secondaryOSD=False):
|
||||
duration /= 1000
|
||||
self._listener.sendLine('display-osd: {}, {}, {}'.format('top-right', duration, message.encode('utf8')))
|
||||
if secondaryOSD == False:
|
||||
self._listener.sendLine('display-osd: {}, {}, {}'.format('top-right', duration, message.encode('utf8')))
|
||||
else:
|
||||
self._listener.sendLine('display-secondary-osd: {}, {}, {}'.format('center', duration, message.encode('utf8')))
|
||||
|
||||
def setSpeed(self, value):
|
||||
self._listener.sendLine("set-rate: {:.2n}".format(value))
|
||||
@ -131,7 +137,10 @@ class VlcPlayer(BasePlayer):
|
||||
self._listener.sendLine("get-filename")
|
||||
|
||||
def lineReceived(self, line):
|
||||
self._client.ui.showDebugMessage("player >> {}".format(line))
|
||||
try:
|
||||
self._client.ui.showDebugMessage("player << {}".format(line))
|
||||
except:
|
||||
pass
|
||||
match, name, value = self.RE_ANSWER.match(line), "", ""
|
||||
if match:
|
||||
name, value = match.group('command'), match.group('argument')
|
||||
@ -340,7 +349,7 @@ class VlcPlayer(BasePlayer):
|
||||
if self.connected:
|
||||
try:
|
||||
self.push(line + "\n")
|
||||
self._client.ui.showDebugMessage("player >> {}".format(line))
|
||||
self.__playerController._client.ui.showDebugMessage("player >> {}".format(line))
|
||||
except:
|
||||
pass
|
||||
if line == "close-vlc":
|
||||
|
||||
@ -136,6 +136,10 @@ class SyncClientProtocol(JSONCommandProtocol):
|
||||
controlPassword = values['password']
|
||||
roomName = values['roomName']
|
||||
self._client.controlledRoomCreated(roomName, controlPassword)
|
||||
elif command == "ready":
|
||||
user, isReady = values["username"], values["isReady"]
|
||||
manuallyInitiated = values["manuallyInitiated"] if values.has_key("manuallyInitiated") else True
|
||||
self._client.setReady(user, isReady, manuallyInitiated)
|
||||
|
||||
def sendSet(self, setting):
|
||||
self.sendMessage({"Set": setting})
|
||||
@ -158,7 +162,8 @@ class SyncClientProtocol(JSONCommandProtocol):
|
||||
userName = user[0]
|
||||
file_ = user[1]['file'] if user[1]['file'] <> {} else None
|
||||
isController = user[1]['controller'] if 'controller' in user[1] else False
|
||||
self._client.userlist.addUser(userName, roomName, file_, noMessage=True, isController=isController)
|
||||
isReady = user[1]['isReady'] if 'isReady' in user[1] else None
|
||||
self._client.userlist.addUser(userName, roomName, file_, noMessage=True, isController=isController, isReady=isReady)
|
||||
self._client.userlist.showUserList()
|
||||
|
||||
def sendList(self):
|
||||
@ -234,6 +239,14 @@ class SyncClientProtocol(JSONCommandProtocol):
|
||||
}
|
||||
})
|
||||
|
||||
def setReady(self, isReady, manuallyInitiated=True):
|
||||
self.sendSet({
|
||||
"ready": {
|
||||
"isReady": isReady,
|
||||
"manuallyInitiated": manuallyInitiated
|
||||
}
|
||||
})
|
||||
|
||||
def handleError(self, error):
|
||||
self.dropWithError(error["message"])
|
||||
|
||||
@ -342,6 +355,9 @@ class SyncServerProtocol(JSONCommandProtocol):
|
||||
password = set_[1]["password"] if set_[1].has_key("password") else None
|
||||
room = set_[1]["room"] if set_[1].has_key("room") else None
|
||||
self._factory.authRoomController(self._watcher, password, room)
|
||||
elif command == "ready":
|
||||
manuallyInitiated = set_[1]['manuallyInitiated'] if set_[1].has_key("manuallyInitiated") else False
|
||||
self._factory.setReady(self._watcher, set_[1]['isReady'], manuallyInitiated=manuallyInitiated)
|
||||
|
||||
def sendSet(self, setting):
|
||||
self.sendMessage({"Set": setting})
|
||||
@ -363,6 +379,16 @@ class SyncServerProtocol(JSONCommandProtocol):
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
def sendSetReady(self, username, isReady, manuallyInitiated=True):
|
||||
self.sendSet({
|
||||
"ready": {
|
||||
"username": username,
|
||||
"isReady": isReady,
|
||||
"manuallyInitiated": manuallyInitiated
|
||||
}
|
||||
})
|
||||
|
||||
def sendUserSetting(self, username, room, file_, event):
|
||||
room = {"name": room.getName()}
|
||||
user = {username: {}}
|
||||
@ -381,7 +407,8 @@ class SyncServerProtocol(JSONCommandProtocol):
|
||||
userFile = {
|
||||
"position": 0,
|
||||
"file": watcher.getFile() if watcher.getFile() else {},
|
||||
"controller": watcher.isController()
|
||||
"controller": watcher.isController(),
|
||||
"isReady": watcher.isReady()
|
||||
}
|
||||
userlist[room.getName()][watcher.getName()] = userFile
|
||||
|
||||
|
||||
@ -14,7 +14,7 @@ import argparse
|
||||
from syncplay.utils import RoomPasswordProvider, NotControlledRoom, RandomStringGenerator, meetsMinVersion
|
||||
|
||||
class SyncFactory(Factory):
|
||||
def __init__(self, password='', motdFilePath=None, isolateRooms=False, salt=None):
|
||||
def __init__(self, password='', motdFilePath=None, isolateRooms=False, salt=None, disableReady=False):
|
||||
print getMessage("welcome-server-notification").format(syncplay.version)
|
||||
if password:
|
||||
password = hashlib.md5(password).hexdigest()
|
||||
@ -24,6 +24,7 @@ class SyncFactory(Factory):
|
||||
print getMessage("no-salt-notification").format(salt)
|
||||
self._salt = salt
|
||||
self._motdFilePath = motdFilePath
|
||||
self.disableReady = disableReady
|
||||
if not isolateRooms:
|
||||
self._roomManager = RoomManager()
|
||||
else:
|
||||
@ -78,6 +79,7 @@ class SyncFactory(Factory):
|
||||
def sendRoomSwitchMessage(self, watcher):
|
||||
l = lambda w: w.sendSetting(watcher.getName(), watcher.getRoom(), None, None)
|
||||
self._roomManager.broadcast(watcher, l)
|
||||
self._roomManager.broadcastRoom(watcher, lambda w: w.sendSetReady(watcher.getName(), watcher.isReady(), False))
|
||||
|
||||
def removeWatcher(self, watcher):
|
||||
if watcher and watcher.getRoom():
|
||||
@ -91,6 +93,7 @@ class SyncFactory(Factory):
|
||||
def sendJoinMessage(self, watcher):
|
||||
l = lambda w: w.sendSetting(watcher.getName(), watcher.getRoom(), None, {"joined": True}) if w != watcher else None
|
||||
self._roomManager.broadcast(watcher, l)
|
||||
self._roomManager.broadcastRoom(watcher, lambda w: w.sendSetReady(watcher.getName(), watcher.isReady(), False))
|
||||
|
||||
def sendFileUpdate(self, watcher):
|
||||
l = lambda w: w.sendSetting(watcher.getName(), watcher.getRoom(), watcher.getFile(), None)
|
||||
@ -125,6 +128,9 @@ class SyncFactory(Factory):
|
||||
except ValueError:
|
||||
self._roomManager.broadcastRoom(watcher, lambda w: w.sendControlledRoomAuthStatus(False, watcher.getName(), room._name))
|
||||
|
||||
def setReady(self, watcher, isReady, manuallyInitiated=True):
|
||||
watcher.setReady(isReady)
|
||||
self._roomManager.broadcastRoom(watcher, lambda w: w.sendSetReady(watcher.getName(), watcher.isReady(), manuallyInitiated))
|
||||
|
||||
class RoomManager(object):
|
||||
def __init__(self):
|
||||
@ -299,6 +305,7 @@ class ControlledRoom(Room):
|
||||
|
||||
class Watcher(object):
|
||||
def __init__(self, server, connector, name):
|
||||
self._ready = None
|
||||
self._server = server
|
||||
self._connector = connector
|
||||
self._name = name
|
||||
@ -322,6 +329,14 @@ class Watcher(object):
|
||||
self._resetStateTimer()
|
||||
self._askForStateUpdate(True, True)
|
||||
|
||||
def setReady(self, ready):
|
||||
self._ready = ready
|
||||
|
||||
def isReady(self):
|
||||
if self._server.disableReady:
|
||||
return None
|
||||
return self._ready
|
||||
|
||||
def getRoom(self):
|
||||
return self._room
|
||||
|
||||
@ -352,6 +367,9 @@ class Watcher(object):
|
||||
def sendControlledRoomAuthStatus(self, success, username, room):
|
||||
self._connector.sendControlledRoomAuthStatus(success, username, room)
|
||||
|
||||
def sendSetReady(self, username, isReady, manuallyInitiated=True):
|
||||
self._connector.sendSetReady(username, isReady, manuallyInitiated)
|
||||
|
||||
def __lt__(self, b):
|
||||
if self.getPosition() is None or self._file is None:
|
||||
return False
|
||||
@ -422,5 +440,6 @@ class ConfigurationGetter(object):
|
||||
self._argparser.add_argument('--port', metavar='port', type=str, nargs='?', help=getMessage("server-port-argument"))
|
||||
self._argparser.add_argument('--password', metavar='password', type=str, nargs='?', help=getMessage("server-password-argument"))
|
||||
self._argparser.add_argument('--isolate-rooms', action='store_true', help=getMessage("server-isolate-room-argument"))
|
||||
self._argparser.add_argument('--disable-ready', action='store_true', help=getMessage("server-disable-ready-argument"))
|
||||
self._argparser.add_argument('--salt', metavar='salt', type=str, nargs='?', help=getMessage("server-salt-argument"))
|
||||
self._argparser.add_argument('--motd-file', metavar='file', type=str, nargs='?', help=getMessage("server-motd-argument"))
|
||||
@ -44,8 +44,11 @@ class ConfigurationGetter(object):
|
||||
"filenamePrivacyMode": constants.PRIVACY_SENDRAW_MODE,
|
||||
"filesizePrivacyMode": constants.PRIVACY_SENDRAW_MODE,
|
||||
"pauseOnLeave": False,
|
||||
"readyAtStart": False,
|
||||
"clearGUIData": False,
|
||||
"language" : "",
|
||||
"checkForUpdatesAutomatically" : None,
|
||||
"lastCheckedForUpdates" : "",
|
||||
"resetConfig" : False,
|
||||
"showOSD" : True,
|
||||
"showOSDWarnings" : True,
|
||||
@ -77,6 +80,7 @@ class ConfigurationGetter(object):
|
||||
"noStore",
|
||||
"dontSlowDownWithMe",
|
||||
"pauseOnLeave",
|
||||
"readyAtStart",
|
||||
"clearGUIData",
|
||||
"rewindOnDesync",
|
||||
"slowOnDesync",
|
||||
@ -90,9 +94,11 @@ class ConfigurationGetter(object):
|
||||
"showDifferentRoomOSD",
|
||||
"showSameRoomOSD",
|
||||
"showNonControllerOSD",
|
||||
"showContactInfo" ,
|
||||
"showDurationNotification"
|
||||
]
|
||||
self._tristate = [
|
||||
"checkForUpdatesAutomatically"
|
||||
]
|
||||
|
||||
self._numeric = [
|
||||
"slowdownThreshold",
|
||||
@ -102,9 +108,9 @@ class ConfigurationGetter(object):
|
||||
|
||||
self._iniStructure = {
|
||||
"server_data": ["host", "port", "password"],
|
||||
"client_settings": ["name", "room", "playerPath", "slowdownThreshold", "rewindThreshold", "fastforwardThreshold", "slowOnDesync", "rewindOnDesync", "fastforwardOnDesync", "dontSlowDownWithMe", "forceGuiPrompt", "filenamePrivacyMode", "filesizePrivacyMode", "pauseOnLeave"],
|
||||
"gui": ["showOSD", "showOSDWarnings", "showSlowdownOSD", "showDifferentRoomOSD", "showSameRoomOSD", "showNonControllerOSD", "showContactInfo" , "showDurationNotification"],
|
||||
"general": ["language"]
|
||||
"client_settings": ["name", "room", "playerPath", "slowdownThreshold", "rewindThreshold", "fastforwardThreshold", "slowOnDesync", "rewindOnDesync", "fastforwardOnDesync", "dontSlowDownWithMe", "forceGuiPrompt", "filenamePrivacyMode", "filesizePrivacyMode", "pauseOnLeave", "readyAtStart"],
|
||||
"gui": ["showOSD", "showOSDWarnings", "showSlowdownOSD", "showDifferentRoomOSD", "showSameRoomOSD", "showNonControllerOSD", "showDurationNotification"],
|
||||
"general": ["language", "checkForUpdatesAutomatically", "lastCheckedForUpdates"]
|
||||
}
|
||||
|
||||
self._playerFactory = PlayerFactory()
|
||||
@ -112,8 +118,10 @@ class ConfigurationGetter(object):
|
||||
def _validateArguments(self):
|
||||
if self._config['resetConfig']:
|
||||
language = self._config['language']
|
||||
checkForUpdatesAutomatically = self._config['checkForUpdatesAutomatically']
|
||||
self._config = self._defaultConfig
|
||||
self._config['language'] = language
|
||||
self._config['checkForUpdatesAutomatically'] = checkForUpdatesAutomatically
|
||||
raise InvalidConfigValue("*"+getMessage("config-cleared-notification"))
|
||||
|
||||
if not isValidLanguage(self._config['language']):
|
||||
@ -137,6 +145,14 @@ class ConfigurationGetter(object):
|
||||
elif self._config[key] == "False":
|
||||
self._config[key] = False
|
||||
|
||||
for key in self._tristate:
|
||||
if self._config[key] == "True":
|
||||
self._config[key] = True
|
||||
elif self._config[key] == "False":
|
||||
self._config[key] = False
|
||||
elif self._config[key] == "None":
|
||||
self._config[key] = None
|
||||
|
||||
for key in self._numeric:
|
||||
self._config[key] = float(self._config[key])
|
||||
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
from PySide import QtCore, QtGui
|
||||
from PySide.QtCore import QSettings, Qt, QCoreApplication
|
||||
from PySide.QtCore import QSettings, Qt, QCoreApplication, QUrl
|
||||
from PySide.QtGui import QApplication, QLineEdit, QCursor, QLabel, QCheckBox, QDesktopServices, QIcon, QImage, QButtonGroup, QRadioButton, QDoubleSpinBox
|
||||
from syncplay.players.playerFactory import PlayerFactory
|
||||
|
||||
from datetime import datetime
|
||||
import os
|
||||
import sys
|
||||
from syncplay.messages import getMessage, getLanguages, setLanguage, getInitialLanguage
|
||||
@ -35,6 +35,15 @@ class ConfigDialog(QtGui.QDialog):
|
||||
pressedclosebutton = False
|
||||
moreToggling = False
|
||||
|
||||
def automaticUpdatePromptCheck(self):
|
||||
if self.automaticupdatesCheckbox.checkState() == Qt.PartiallyChecked and not self.nostoreCheckbox.isChecked():
|
||||
reply = QtGui.QMessageBox.question(self, "Syncplay",
|
||||
getMessage("promptforupdate-label"), QtGui.QMessageBox.StandardButton.Yes | QtGui.QMessageBox.StandardButton.No)
|
||||
if reply == QtGui.QMessageBox.Yes:
|
||||
self.automaticupdatesCheckbox.setChecked(True)
|
||||
else:
|
||||
self.automaticupdatesCheckbox.setChecked(False)
|
||||
|
||||
def moreToggled(self):
|
||||
if self.moreToggling == False:
|
||||
self.moreToggling = True
|
||||
@ -43,7 +52,6 @@ class ConfigDialog(QtGui.QDialog):
|
||||
self.tabListFrame.show()
|
||||
self.resetButton.show()
|
||||
self.nostoreCheckbox.show()
|
||||
self.alwaysshowCheckbox.show()
|
||||
self.saveMoreState(True)
|
||||
self.tabListWidget.setCurrentRow(0)
|
||||
self.ensureTabListIsVisible()
|
||||
@ -51,7 +59,6 @@ class ConfigDialog(QtGui.QDialog):
|
||||
self.tabListFrame.hide()
|
||||
self.resetButton.hide()
|
||||
self.nostoreCheckbox.hide()
|
||||
self.alwaysshowCheckbox.hide()
|
||||
self.saveMoreState(False)
|
||||
self.stackedLayout.setCurrentIndex(0)
|
||||
|
||||
@ -68,7 +75,7 @@ class ConfigDialog(QtGui.QDialog):
|
||||
self.runButton.setText(getMessage("storeandrun-label"))
|
||||
|
||||
def openHelp(self):
|
||||
self.QtGui.QDesktopServices.openUrl("http://syncplay.pl/guide/client/")
|
||||
self.QtGui.QDesktopServices.openUrl(QUrl("http://syncplay.pl/guide/client/"))
|
||||
|
||||
def _isURL(self, path):
|
||||
if path is None:
|
||||
@ -170,6 +177,17 @@ class ConfigDialog(QtGui.QDialog):
|
||||
if fileName:
|
||||
self.executablepathCombobox.setEditText(os.path.normpath(fileName))
|
||||
|
||||
def loadLastUpdateCheckDate(self):
|
||||
settings = QSettings("Syncplay", "Interface")
|
||||
settings.beginGroup("Update")
|
||||
self.lastCheckedForUpdates = settings.value("lastChecked", None)
|
||||
if self.lastCheckedForUpdates:
|
||||
if self.config["lastCheckedForUpdates"] is not None and self.config["lastCheckedForUpdates"] is not "":
|
||||
if self.lastCheckedForUpdates > datetime.strptime(self.config["lastCheckedForUpdates"], "%Y-%m-%d %H:%M:%S.%f"):
|
||||
self.config["lastCheckedForUpdates"] = str(self.lastCheckedForUpdates)
|
||||
else:
|
||||
self.config["lastCheckedForUpdates"] = str(self.lastCheckedForUpdates)
|
||||
|
||||
def loadMediaBrowseSettings(self):
|
||||
settings = QSettings("Syncplay", "MediaBrowseDialog")
|
||||
settings.beginGroup("MediaBrowseDialog")
|
||||
@ -218,6 +236,9 @@ class ConfigDialog(QtGui.QDialog):
|
||||
self.saveMediaBrowseSettings()
|
||||
|
||||
def _saveDataAndLeave(self):
|
||||
self.automaticUpdatePromptCheck()
|
||||
self.loadLastUpdateCheckDate()
|
||||
|
||||
self.processWidget(self, lambda w: self.saveValues(w))
|
||||
if self.hostTextbox.text():
|
||||
self.config['host'] = self.hostTextbox.text() if ":" in self.hostTextbox.text() else self.hostTextbox.text() + ":" + unicode(constants.DEFAULT_PORT)
|
||||
@ -293,7 +314,12 @@ class ConfigDialog(QtGui.QDialog):
|
||||
inverted = True
|
||||
else:
|
||||
inverted = False
|
||||
widget.setChecked(self.config[valueName] != inverted)
|
||||
if self.config[valueName] is None:
|
||||
widget.setTristate(True)
|
||||
widget.setCheckState(Qt.PartiallyChecked)
|
||||
widget.stateChanged.connect(lambda: widget.setTristate(False))
|
||||
else:
|
||||
widget.setChecked(self.config[valueName] != inverted)
|
||||
elif isinstance(widget, QRadioButton):
|
||||
radioName, radioValue = valueName.split(constants.CONFIG_NAME_MARKER)[1].split(constants.CONFIG_VALUE_MARKER)
|
||||
if self.config[radioName] == radioValue:
|
||||
@ -307,12 +333,15 @@ class ConfigDialog(QtGui.QDialog):
|
||||
return
|
||||
|
||||
if isinstance(widget, QCheckBox) and widget.objectName():
|
||||
if valueName[:1] == constants.INVERTED_STATE_MARKER:
|
||||
valueName = valueName[1:]
|
||||
inverted = True
|
||||
if widget.checkState() == Qt.PartiallyChecked:
|
||||
self.config[valueName] = None
|
||||
else:
|
||||
inverted = False
|
||||
self.config[valueName] = widget.isChecked() != inverted
|
||||
if valueName[:1] == constants.INVERTED_STATE_MARKER:
|
||||
valueName = valueName[1:]
|
||||
inverted = True
|
||||
else:
|
||||
inverted = False
|
||||
self.config[valueName] = widget.isChecked() != inverted
|
||||
elif isinstance(widget, QRadioButton):
|
||||
radioName, radioValue = valueName.split(constants.CONFIG_NAME_MARKER)[1].split(constants.CONFIG_VALUE_MARKER)
|
||||
if widget.isChecked():
|
||||
@ -434,18 +463,104 @@ class ConfigDialog(QtGui.QDialog):
|
||||
self.connectionSettingsGroup.setMaximumHeight(self.connectionSettingsGroup.minimumSizeHint().height())
|
||||
self.basicOptionsLayout.setAlignment(Qt.AlignTop)
|
||||
self.basicOptionsLayout.addWidget(self.connectionSettingsGroup)
|
||||
self.basicOptionsLayout.addSpacing(17)
|
||||
self.basicOptionsLayout.addSpacing(5)
|
||||
self.mediaplayerSettingsGroup.setMaximumHeight(self.mediaplayerSettingsGroup.minimumSizeHint().height())
|
||||
self.basicOptionsLayout.addWidget(self.mediaplayerSettingsGroup)
|
||||
|
||||
self.basicOptionsFrame.setLayout(self.basicOptionsLayout)
|
||||
self.stackedLayout.addWidget(self.basicOptionsFrame)
|
||||
|
||||
def addMiscTab(self):
|
||||
self.miscFrame = QtGui.QFrame()
|
||||
self.miscLayout = QtGui.QVBoxLayout()
|
||||
self.miscFrame.setLayout(self.miscLayout)
|
||||
|
||||
self.coreSettingsGroup = QtGui.QGroupBox(getMessage("core-behaviour-title"))
|
||||
self.coreSettingsLayout = QtGui.QVBoxLayout()
|
||||
self.coreSettingsGroup.setLayout(self.coreSettingsLayout)
|
||||
|
||||
self.pauseonleaveCheckbox = QCheckBox(getMessage("pauseonleave-label"))
|
||||
self.pauseonleaveCheckbox.setObjectName("pauseOnLeave")
|
||||
self.coreSettingsLayout.addWidget(self.pauseonleaveCheckbox)
|
||||
|
||||
self.readyatstartCheckbox = QCheckBox(getMessage("readyatstart-label"))
|
||||
self.readyatstartCheckbox.setObjectName("readyAtStart")
|
||||
self.coreSettingsLayout.addWidget(self.readyatstartCheckbox)
|
||||
|
||||
self.internalSettingsGroup = QtGui.QGroupBox(getMessage("syncplay-internals-title"))
|
||||
self.internalSettingsLayout = QtGui.QVBoxLayout()
|
||||
self.internalSettingsGroup.setLayout(self.internalSettingsLayout)
|
||||
|
||||
self.alwaysshowCheckbox = QCheckBox(getMessage("forceguiprompt-label"))
|
||||
self.alwaysshowCheckbox.setObjectName(constants.INVERTED_STATE_MARKER + "forceGuiPrompt")
|
||||
self.internalSettingsLayout.addWidget(self.alwaysshowCheckbox)
|
||||
|
||||
self.automaticupdatesCheckbox = QCheckBox(getMessage("checkforupdatesautomatically-label"))
|
||||
self.automaticupdatesCheckbox.setObjectName("checkForUpdatesAutomatically")
|
||||
self.internalSettingsLayout.addWidget(self.automaticupdatesCheckbox)
|
||||
|
||||
### Privacy:
|
||||
|
||||
self.privacySettingsGroup = QtGui.QGroupBox(getMessage("privacy-title"))
|
||||
self.privacySettingsLayout = QtGui.QVBoxLayout()
|
||||
self.privacySettingsFrame = QtGui.QFrame()
|
||||
self.privacyFrame = QtGui.QFrame()
|
||||
self.privacyLayout = QtGui.QGridLayout()
|
||||
|
||||
self.filenameprivacyLabel = QLabel(getMessage("filename-privacy-label"), self)
|
||||
self.filenameprivacyButtonGroup = QButtonGroup()
|
||||
self.filenameprivacySendRawOption = QRadioButton(getMessage("privacy-sendraw-option"))
|
||||
self.filenameprivacySendHashedOption = QRadioButton(getMessage("privacy-sendhashed-option"))
|
||||
self.filenameprivacyDontSendOption = QRadioButton(getMessage("privacy-dontsend-option"))
|
||||
self.filenameprivacyButtonGroup.addButton(self.filenameprivacySendRawOption)
|
||||
self.filenameprivacyButtonGroup.addButton(self.filenameprivacySendHashedOption)
|
||||
self.filenameprivacyButtonGroup.addButton(self.filenameprivacyDontSendOption)
|
||||
|
||||
self.filesizeprivacyLabel = QLabel(getMessage("filesize-privacy-label"), self)
|
||||
self.filesizeprivacyButtonGroup = QButtonGroup()
|
||||
self.filesizeprivacySendRawOption = QRadioButton(getMessage("privacy-sendraw-option"))
|
||||
self.filesizeprivacySendHashedOption = QRadioButton(getMessage("privacy-sendhashed-option"))
|
||||
self.filesizeprivacyDontSendOption = QRadioButton(getMessage("privacy-dontsend-option"))
|
||||
self.filesizeprivacyButtonGroup.addButton(self.filesizeprivacySendRawOption)
|
||||
self.filesizeprivacyButtonGroup.addButton(self.filesizeprivacySendHashedOption)
|
||||
self.filesizeprivacyButtonGroup.addButton(self.filesizeprivacyDontSendOption)
|
||||
|
||||
self.filenameprivacyLabel.setObjectName("filename-privacy")
|
||||
self.filenameprivacySendRawOption.setObjectName("privacy-sendraw" + constants.CONFIG_NAME_MARKER + "filenamePrivacyMode" + constants.CONFIG_VALUE_MARKER + constants.PRIVACY_SENDRAW_MODE)
|
||||
self.filenameprivacySendHashedOption.setObjectName("privacy-sendhashed" + constants.CONFIG_NAME_MARKER + "filenamePrivacyMode" + constants.CONFIG_VALUE_MARKER + constants.PRIVACY_SENDHASHED_MODE)
|
||||
self.filenameprivacyDontSendOption.setObjectName("privacy-dontsend" + constants.CONFIG_NAME_MARKER + "filenamePrivacyMode" + constants.CONFIG_VALUE_MARKER + constants.PRIVACY_DONTSEND_MODE)
|
||||
self.filesizeprivacyLabel.setObjectName("filesize-privacy")
|
||||
self.filesizeprivacySendRawOption.setObjectName("privacy-sendraw" + constants.CONFIG_NAME_MARKER + "filesizePrivacyMode" + constants.CONFIG_VALUE_MARKER + constants.PRIVACY_SENDRAW_MODE)
|
||||
self.filesizeprivacySendHashedOption.setObjectName("privacy-sendhashed" + constants.CONFIG_NAME_MARKER + "filesizePrivacyMode" + constants.CONFIG_VALUE_MARKER + constants.PRIVACY_SENDHASHED_MODE)
|
||||
self.filesizeprivacyDontSendOption.setObjectName("privacy-dontsend" + constants.CONFIG_NAME_MARKER + "filesizePrivacyMode" + constants.CONFIG_VALUE_MARKER + constants.PRIVACY_DONTSEND_MODE)
|
||||
|
||||
self.privacyLayout.addWidget(self.filenameprivacyLabel, 1, 0)
|
||||
self.privacyLayout.addWidget(self.filenameprivacySendRawOption, 1, 1, Qt.AlignLeft)
|
||||
self.privacyLayout.addWidget(self.filenameprivacySendHashedOption, 1, 2, Qt.AlignLeft)
|
||||
self.privacyLayout.addWidget(self.filenameprivacyDontSendOption, 1, 3, Qt.AlignLeft)
|
||||
self.privacyLayout.addWidget(self.filesizeprivacyLabel, 2, 0)
|
||||
self.privacyLayout.addWidget(self.filesizeprivacySendRawOption, 2, 1, Qt.AlignLeft)
|
||||
self.privacyLayout.addWidget(self.filesizeprivacySendHashedOption, 2, 2, Qt.AlignLeft)
|
||||
self.privacyLayout.addWidget(self.filesizeprivacyDontSendOption, 2, 3, Qt.AlignLeft)
|
||||
|
||||
self.privacyFrame.setLayout(self.privacyLayout)
|
||||
self.privacySettingsGroup.setLayout(self.privacyLayout)
|
||||
self.privacySettingsGroup.setMaximumHeight(self.privacySettingsGroup.minimumSizeHint().height())
|
||||
self.privacySettingsLayout.addWidget(self.privacySettingsGroup)
|
||||
self.privacySettingsLayout.setAlignment(Qt.AlignTop)
|
||||
self.privacyFrame.setLayout(self.privacySettingsLayout)
|
||||
|
||||
self.miscLayout.addWidget(self.coreSettingsGroup)
|
||||
self.miscLayout.addWidget(self.internalSettingsGroup)
|
||||
self.miscLayout.addWidget(self.privacySettingsGroup)
|
||||
self.miscLayout.setAlignment(Qt.AlignTop)
|
||||
self.stackedLayout.addWidget(self.miscFrame)
|
||||
|
||||
def addSyncTab(self):
|
||||
self.syncSettingsFrame = QtGui.QFrame()
|
||||
self.syncSettingsLayout = QtGui.QVBoxLayout()
|
||||
|
||||
self.desyncSettingsGroup = QtGui.QGroupBox(getMessage("sync-lagging-title"))
|
||||
self.desyncSettingsGroup = QtGui.QGroupBox(getMessage("sync-otherslagging-title"))
|
||||
self.desyncOptionsFrame = QtGui.QFrame()
|
||||
self.desyncSettingsOptionsLayout = QtGui.QHBoxLayout()
|
||||
config = self.config
|
||||
@ -534,34 +649,31 @@ class ConfigDialog(QtGui.QDialog):
|
||||
self.desyncSettingsLayout.setAlignment(Qt.AlignLeft)
|
||||
self.desyncSettingsGroup.setLayout(self.desyncSettingsLayout)
|
||||
self.desyncSettingsOptionsLayout.addWidget(self.desyncFrame)
|
||||
self.syncSettingsLayout.addWidget(self.desyncSettingsGroup)
|
||||
|
||||
self.desyncFrame.setLayout(self.syncSettingsLayout)
|
||||
|
||||
self.othersyncSettingsGroup = QtGui.QGroupBox(getMessage("sync-other-title"))
|
||||
self.othersyncSettingsGroup = QtGui.QGroupBox(getMessage("sync-youlaggging-title"))
|
||||
self.othersyncOptionsFrame = QtGui.QFrame()
|
||||
self.othersyncSettingsLayout = QtGui.QGridLayout()
|
||||
|
||||
self.pauseonleaveCheckbox = QCheckBox(getMessage("pauseonleave-label"))
|
||||
self.othersyncSettingsLayout.addWidget(self.pauseonleaveCheckbox, 1, 0, 1, 2, Qt.AlignLeft)
|
||||
self.pauseonleaveCheckbox.setObjectName("pauseOnLeave")
|
||||
|
||||
self.dontslowwithmeCheckbox = QCheckBox(getMessage("dontslowdownwithme-label"))
|
||||
self.dontslowwithmeCheckbox.setObjectName("dontSlowDownWithMe")
|
||||
|
||||
self.othersyncSettingsLayout.addWidget(self.dontslowwithmeCheckbox, 2, 0, 1, 2, Qt.AlignLeft)
|
||||
self.othersyncSettingsLayout.addWidget(self.dontslowwithmeCheckbox, 3, 0, 1, 2, Qt.AlignLeft)
|
||||
|
||||
self.fastforwardThresholdLabel.setObjectName("fastforward-threshold")
|
||||
self.fastforwardThresholdSpinbox.setObjectName("fastforward-threshold")
|
||||
|
||||
self.othersyncSettingsLayout.addWidget(self.fastforwardCheckbox, 3, 0,1,2, Qt.AlignLeft)
|
||||
self.othersyncSettingsLayout.addWidget(self.fastforwardThresholdLabel, 4, 0, 1, 1, Qt.AlignLeft)
|
||||
self.othersyncSettingsLayout.addWidget(self.fastforwardThresholdSpinbox, 4, 1, Qt.AlignLeft)
|
||||
self.othersyncSettingsLayout.setAlignment(Qt.AlignLeft)
|
||||
self.othersyncSettingsLayout.addWidget(self.fastforwardCheckbox, 4, 0,1,2, Qt.AlignLeft)
|
||||
self.othersyncSettingsLayout.addWidget(self.fastforwardThresholdLabel, 5, 0, 1, 1, Qt.AlignLeft)
|
||||
self.othersyncSettingsLayout.addWidget(self.fastforwardThresholdSpinbox, 5, 1, Qt.AlignLeft)
|
||||
self.subitems['fastforwardOnDesync'] = ["fastforward-threshold"]
|
||||
|
||||
self.othersyncSettingsGroup.setLayout(self.othersyncSettingsLayout)
|
||||
self.othersyncSettingsGroup.setMaximumHeight(self.othersyncSettingsGroup.minimumSizeHint().height())
|
||||
self.syncSettingsLayout.addWidget(self.othersyncSettingsGroup)
|
||||
|
||||
self.syncSettingsLayout.addWidget(self.desyncSettingsGroup)
|
||||
self.syncSettingsFrame.setLayout(self.syncSettingsLayout)
|
||||
self.desyncSettingsGroup.setMaximumHeight(self.desyncSettingsGroup.minimumSizeHint().height())
|
||||
self.syncSettingsLayout.setAlignment(Qt.AlignTop)
|
||||
@ -570,6 +682,7 @@ class ConfigDialog(QtGui.QDialog):
|
||||
def addMessageTab(self):
|
||||
self.messageFrame = QtGui.QFrame()
|
||||
self.messageLayout = QtGui.QVBoxLayout()
|
||||
self.messageLayout.setAlignment(Qt.AlignTop)
|
||||
|
||||
# OSD
|
||||
self.osdSettingsGroup = QtGui.QGroupBox(getMessage("messages-osd-title"))
|
||||
@ -615,18 +728,20 @@ class ConfigDialog(QtGui.QDialog):
|
||||
# Other display
|
||||
|
||||
self.displaySettingsGroup = QtGui.QGroupBox(getMessage("messages-other-title"))
|
||||
self.displaySettingsLayout = QtGui.QGridLayout()
|
||||
self.displaySettingsLayout.setAlignment(Qt.AlignTop)
|
||||
self.displaySettingsLayout = QtGui.QVBoxLayout()
|
||||
self.displaySettingsLayout.setAlignment(Qt.AlignTop & Qt.AlignLeft)
|
||||
self.displaySettingsFrame = QtGui.QFrame()
|
||||
|
||||
self.showDurationNotificationCheckbox = QCheckBox(getMessage("showdurationnotification-label"))
|
||||
self.showDurationNotificationCheckbox.setObjectName("showDurationNotification")
|
||||
self.displaySettingsLayout.addWidget(self.showDurationNotificationCheckbox, 0, 0, 1, 2)
|
||||
|
||||
self.showcontactinfoCheckbox = QCheckBox(getMessage("showcontactinfo-label"))
|
||||
self.showcontactinfoCheckbox.setObjectName("showContactInfo")
|
||||
self.displaySettingsLayout.addWidget(self.showcontactinfoCheckbox, 1, 0, 1, 2)
|
||||
self.displaySettingsLayout.addWidget(self.showDurationNotificationCheckbox)
|
||||
|
||||
self.languageFrame = QtGui.QFrame()
|
||||
self.languageLayout = QtGui.QHBoxLayout()
|
||||
self.languageLayout.setContentsMargins(0, 0, 0, 0)
|
||||
self.languageFrame.setLayout(self.languageLayout)
|
||||
self.languageFrame.setSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Minimum)
|
||||
self.languageLayout.setAlignment(Qt.AlignTop & Qt.AlignLeft)
|
||||
self.languageLabel = QLabel(getMessage("language-label"), self)
|
||||
self.languageCombobox = QtGui.QComboBox(self)
|
||||
self.languageCombobox.addItem(getMessage("automatic-language").format(getMessage("LANGUAGE", getInitialLanguage())))
|
||||
@ -637,73 +752,23 @@ class ConfigDialog(QtGui.QDialog):
|
||||
if lang == self.config['language']:
|
||||
self.languageCombobox.setCurrentIndex(self.languageCombobox.count()-1)
|
||||
self.languageCombobox.currentIndexChanged.connect(self.languageChanged)
|
||||
self.displaySettingsLayout.addWidget(self.languageLabel, 2, 0, 1, 1)
|
||||
self.displaySettingsLayout.addWidget(self.languageCombobox, 2, 1, 1, 1)
|
||||
self.languageLayout.addWidget(self.languageLabel, 1, 0)
|
||||
self.languageLayout.addWidget(self.languageCombobox, 1, 1)
|
||||
self.displaySettingsLayout.addWidget(self.languageFrame)
|
||||
|
||||
self.languageLabel.setObjectName("language")
|
||||
self.languageCombobox.setObjectName("language")
|
||||
|
||||
self.languageFrame.setMaximumWidth(self.languageFrame.minimumSizeHint().width())
|
||||
|
||||
self.displaySettingsGroup.setLayout(self.displaySettingsLayout)
|
||||
self.displaySettingsGroup.setMaximumHeight(self.displaySettingsGroup.minimumSizeHint().height())
|
||||
self.displaySettingsLayout.setAlignment(Qt.AlignTop)
|
||||
self.displaySettingsLayout.setAlignment(Qt.AlignTop & Qt.AlignLeft)
|
||||
self.messageLayout.addWidget(self.displaySettingsGroup)
|
||||
|
||||
# messageFrame
|
||||
self.messageFrame.setLayout(self.messageLayout)
|
||||
self.stackedLayout.addWidget(self.messageFrame)
|
||||
|
||||
def addPrivacyTab(self):
|
||||
self.privacySettingsGroup = QtGui.QGroupBox(getMessage("privacy-title"))
|
||||
self.privacySettingsLayout = QtGui.QVBoxLayout()
|
||||
self.privacySettingsFrame = QtGui.QFrame()
|
||||
self.privacyFrame = QtGui.QFrame()
|
||||
self.privacyLayout = QtGui.QGridLayout()
|
||||
|
||||
self.filenameprivacyLabel = QLabel(getMessage("filename-privacy-label"), self)
|
||||
self.filenameprivacyButtonGroup = QButtonGroup()
|
||||
self.filenameprivacySendRawOption = QRadioButton(getMessage("privacy-sendraw-option"))
|
||||
self.filenameprivacySendHashedOption = QRadioButton(getMessage("privacy-sendhashed-option"))
|
||||
self.filenameprivacyDontSendOption = QRadioButton(getMessage("privacy-dontsend-option"))
|
||||
self.filenameprivacyButtonGroup.addButton(self.filenameprivacySendRawOption)
|
||||
self.filenameprivacyButtonGroup.addButton(self.filenameprivacySendHashedOption)
|
||||
self.filenameprivacyButtonGroup.addButton(self.filenameprivacyDontSendOption)
|
||||
|
||||
self.filesizeprivacyLabel = QLabel(getMessage("filesize-privacy-label"), self)
|
||||
self.filesizeprivacyButtonGroup = QButtonGroup()
|
||||
self.filesizeprivacySendRawOption = QRadioButton(getMessage("privacy-sendraw-option"))
|
||||
self.filesizeprivacySendHashedOption = QRadioButton(getMessage("privacy-sendhashed-option"))
|
||||
self.filesizeprivacyDontSendOption = QRadioButton(getMessage("privacy-dontsend-option"))
|
||||
self.filesizeprivacyButtonGroup.addButton(self.filesizeprivacySendRawOption)
|
||||
self.filesizeprivacyButtonGroup.addButton(self.filesizeprivacySendHashedOption)
|
||||
self.filesizeprivacyButtonGroup.addButton(self.filesizeprivacyDontSendOption)
|
||||
|
||||
self.filenameprivacyLabel.setObjectName("filename-privacy")
|
||||
self.filenameprivacySendRawOption.setObjectName("privacy-sendraw" + constants.CONFIG_NAME_MARKER + "filenamePrivacyMode" + constants.CONFIG_VALUE_MARKER + constants.PRIVACY_SENDRAW_MODE)
|
||||
self.filenameprivacySendHashedOption.setObjectName("privacy-sendhashed" + constants.CONFIG_NAME_MARKER + "filenamePrivacyMode" + constants.CONFIG_VALUE_MARKER + constants.PRIVACY_SENDHASHED_MODE)
|
||||
self.filenameprivacyDontSendOption.setObjectName("privacy-dontsend" + constants.CONFIG_NAME_MARKER + "filenamePrivacyMode" + constants.CONFIG_VALUE_MARKER + constants.PRIVACY_DONTSEND_MODE)
|
||||
self.filesizeprivacyLabel.setObjectName("filesize-privacy")
|
||||
self.filesizeprivacySendRawOption.setObjectName("privacy-sendraw" + constants.CONFIG_NAME_MARKER + "filesizePrivacyMode" + constants.CONFIG_VALUE_MARKER + constants.PRIVACY_SENDRAW_MODE)
|
||||
self.filesizeprivacySendHashedOption.setObjectName("privacy-sendhashed" + constants.CONFIG_NAME_MARKER + "filesizePrivacyMode" + constants.CONFIG_VALUE_MARKER + constants.PRIVACY_SENDHASHED_MODE)
|
||||
self.filesizeprivacyDontSendOption.setObjectName("privacy-dontsend" + constants.CONFIG_NAME_MARKER + "filesizePrivacyMode" + constants.CONFIG_VALUE_MARKER + constants.PRIVACY_DONTSEND_MODE)
|
||||
|
||||
self.privacyLayout.addWidget(self.filenameprivacyLabel, 1, 0)
|
||||
self.privacyLayout.addWidget(self.filenameprivacySendRawOption, 1, 1, Qt.AlignLeft)
|
||||
self.privacyLayout.addWidget(self.filenameprivacySendHashedOption, 1, 2, Qt.AlignLeft)
|
||||
self.privacyLayout.addWidget(self.filenameprivacyDontSendOption, 1, 3, Qt.AlignLeft)
|
||||
self.privacyLayout.addWidget(self.filesizeprivacyLabel, 2, 0)
|
||||
self.privacyLayout.addWidget(self.filesizeprivacySendRawOption, 2, 1, Qt.AlignLeft)
|
||||
self.privacyLayout.addWidget(self.filesizeprivacySendHashedOption, 2, 2, Qt.AlignLeft)
|
||||
self.privacyLayout.addWidget(self.filesizeprivacyDontSendOption, 2, 3, Qt.AlignLeft)
|
||||
|
||||
self.privacyFrame.setLayout(self.privacyLayout)
|
||||
self.privacySettingsGroup.setLayout(self.privacyLayout)
|
||||
self.privacySettingsGroup.setMaximumHeight(self.privacySettingsGroup.minimumSizeHint().height())
|
||||
self.privacySettingsLayout.addWidget(self.privacySettingsGroup)
|
||||
self.privacySettingsLayout.setAlignment(Qt.AlignTop)
|
||||
self.privacyFrame.setLayout(self.privacySettingsLayout)
|
||||
self.stackedLayout.addWidget(self.privacyFrame)
|
||||
|
||||
def addBottomLayout(self):
|
||||
config = self.config
|
||||
resourcespath = self.resourcespath
|
||||
@ -738,12 +803,12 @@ class ConfigDialog(QtGui.QDialog):
|
||||
|
||||
self.nostoreCheckbox = QCheckBox(getMessage("nostore-label"))
|
||||
self.bottomCheckboxLayout.addWidget(self.showmoreCheckbox)
|
||||
self.bottomCheckboxLayout.addWidget(self.alwaysshowCheckbox, 0, 1, Qt.AlignLeft)
|
||||
self.bottomCheckboxLayout.addWidget(self.nostoreCheckbox, 0, 2, Qt.AlignRight)
|
||||
self.alwaysshowCheckbox.setObjectName(constants.INVERTED_STATE_MARKER + "forceGuiPrompt")
|
||||
self.nostoreCheckbox.setObjectName("noStore")
|
||||
self.nostoreCheckbox.toggled.connect(self.runButtonTextUpdate)
|
||||
self.bottomCheckboxFrame.setLayout(self.bottomCheckboxLayout)
|
||||
|
||||
self.mainLayout.addWidget(self.bottomCheckboxFrame, 2, 0, 1, 2)
|
||||
|
||||
def tabList(self):
|
||||
@ -751,9 +816,9 @@ class ConfigDialog(QtGui.QDialog):
|
||||
self.tabListFrame = QtGui.QFrame()
|
||||
self.tabListWidget = QtGui.QListWidget()
|
||||
self.tabListWidget.addItem(QtGui.QListWidgetItem(QtGui.QIcon(self.resourcespath + "house.png"),getMessage("basics-label")))
|
||||
self.tabListWidget.addItem(QtGui.QListWidgetItem(QtGui.QIcon(self.resourcespath + "cog.png"),getMessage("misc-label")))
|
||||
self.tabListWidget.addItem(QtGui.QListWidgetItem(QtGui.QIcon(self.resourcespath + "film_link.png"),getMessage("sync-label")))
|
||||
self.tabListWidget.addItem(QtGui.QListWidgetItem(QtGui.QIcon(self.resourcespath + "comments.png"),getMessage("messages-label")))
|
||||
self.tabListWidget.addItem(QtGui.QListWidgetItem(QtGui.QIcon(self.resourcespath + "eye.png"),getMessage("privacy-label")))
|
||||
self.tabListLayout.addWidget(self.tabListWidget)
|
||||
self.tabListFrame.setLayout(self.tabListLayout)
|
||||
self.tabListFrame.setFixedWidth(self.tabListFrame.minimumSizeHint().width())
|
||||
@ -783,7 +848,6 @@ class ConfigDialog(QtGui.QDialog):
|
||||
self.ensureTabListIsVisible()
|
||||
self.setFixedWidth(self.minimumSizeHint().width())
|
||||
self.executablepathCombobox.setFixedWidth(self.mediapathTextbox.width())
|
||||
self.languageLabel.setFixedWidth(self.languageLabel.width())
|
||||
|
||||
def clearGUIData(self, leaveMore=False):
|
||||
settings = QSettings("Syncplay", "PlayerList")
|
||||
@ -792,6 +856,10 @@ class ConfigDialog(QtGui.QDialog):
|
||||
settings.clear()
|
||||
settings = QSettings("Syncplay", "MainWindow")
|
||||
settings.clear()
|
||||
settings = QSettings("Syncplay", "Interface")
|
||||
settings.beginGroup("Update")
|
||||
settings.setValue("lastChecked", None)
|
||||
settings.endGroup()
|
||||
if not leaveMore:
|
||||
settings = QSettings("Syncplay", "MoreSettings")
|
||||
settings.clear()
|
||||
@ -835,9 +903,9 @@ class ConfigDialog(QtGui.QDialog):
|
||||
self.mainLayout.setContentsMargins(0,0,0,0)
|
||||
|
||||
self.addBasicTab()
|
||||
self.addMiscTab()
|
||||
self.addSyncTab()
|
||||
self.addMessageTab()
|
||||
self.addPrivacyTab()
|
||||
self.tabList()
|
||||
|
||||
self.mainLayout.addWidget(self.stackedFrame, 0, 1)
|
||||
@ -847,7 +915,6 @@ class ConfigDialog(QtGui.QDialog):
|
||||
if self.getMoreState() == False:
|
||||
self.tabListFrame.hide()
|
||||
self.nostoreCheckbox.hide()
|
||||
self.alwaysshowCheckbox.hide()
|
||||
self.resetButton.hide()
|
||||
else:
|
||||
self.showmoreCheckbox.setChecked(True)
|
||||
|
||||
@ -39,6 +39,9 @@ class ConsoleUI(threading.Thread):
|
||||
def updateRoomName(self, room=""):
|
||||
pass
|
||||
|
||||
def updateAutoPlayState(self, newState):
|
||||
pass
|
||||
|
||||
def promptFor(self, prompt=">", message=""):
|
||||
if message <> "":
|
||||
print(message)
|
||||
@ -54,18 +57,21 @@ class ConsoleUI(threading.Thread):
|
||||
for user in rooms[room]:
|
||||
userflags = u""
|
||||
if user.isController():
|
||||
userflags = userflags + u"(Controller) "
|
||||
userflags += u"({}) ".format(getMessage("controller-userlist-userflag"))
|
||||
if user.isReady():
|
||||
userflags += u"({}) ".format(getMessage("ready-userlist-userflag"))
|
||||
|
||||
username = userflags + u"*<{}>*".format(user.username) if user == currentUser else userflags + u"<{}>".format(user.username)
|
||||
if user.file:
|
||||
message = u"{} is playing:".format(username)
|
||||
message = getMessage("userlist-playing-notification").format(username)
|
||||
self.showMessage(message, True)
|
||||
message = u" File: '{}' ({})".format(user.file['name'], formatTime(user.file['duration']))
|
||||
message = u" {}: '{}' ({})".format(getMessage("userlist-file-notification"),user.file['name'], formatTime(user.file['duration']))
|
||||
if currentUser.file:
|
||||
if user.file['name'] == currentUser.file['name'] and user.file['size'] != currentUser.file['size']:
|
||||
message += u" (their file size is different from yours!)"
|
||||
message += getMessage("different-filesize-notification")
|
||||
self.showMessage(message, True)
|
||||
else:
|
||||
message = u"{} is not playing a file".format(username)
|
||||
message = getMessage("no-file-played-notification").format(username)
|
||||
self.showMessage(message, True)
|
||||
|
||||
def userListChange(self):
|
||||
@ -149,6 +155,8 @@ class ConsoleUI(threading.Thread):
|
||||
elif command.group('command') in constants.COMMANDS_AUTH:
|
||||
controlpassword = command.group('parameter')
|
||||
self._syncplayClient.identifyAsController(controlpassword)
|
||||
elif command.group('command') in constants.COMMANDS_TOGGLE:
|
||||
self._syncplayClient.toggleReady()
|
||||
else:
|
||||
if self._tryAdvancedCommands(data):
|
||||
return
|
||||
@ -161,6 +169,7 @@ class ConsoleUI(threading.Thread):
|
||||
self.showMessage(getMessage("commandlist-notification/pause"), True)
|
||||
self.showMessage(getMessage("commandlist-notification/seek"), True)
|
||||
self.showMessage(getMessage("commandlist-notification/help"), True)
|
||||
self.showMessage(getMessage("commandlist-notification/toggle"), True)
|
||||
self.showMessage(getMessage("commandlist-notification/create"), True)
|
||||
self.showMessage(getMessage("commandlist-notification/auth"), True)
|
||||
self.showMessage(getMessage("syncplay-version-notification").format(syncplay.version), True)
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
from PySide import QtGui
|
||||
from PySide.QtCore import Qt, QSettings, QSize, QPoint
|
||||
from PySide.QtCore import Qt, QSettings, QSize, QPoint, QUrl
|
||||
from syncplay import utils, constants, version
|
||||
from syncplay.messages import getMessage
|
||||
import sys
|
||||
import time
|
||||
from datetime import datetime
|
||||
import re
|
||||
import os
|
||||
from syncplay.utils import formatTime, sameFilename, sameFilesize, sameFileduration, RoomPasswordProvider, formatSize
|
||||
lastCheckedForUpdates = None
|
||||
|
||||
class UserlistItemDelegate(QtGui.QStyledItemDelegate):
|
||||
def __init__(self):
|
||||
@ -74,13 +76,10 @@ class MainWindow(QtGui.QMainWindow):
|
||||
self.roomInput.setText(self._syncplayClient.getRoom())
|
||||
self.config = self._syncplayClient.getConfig()
|
||||
try:
|
||||
if self.contactLabel and not self.config['showContactInfo']:
|
||||
self.contactLabel.hide()
|
||||
if not constants.SHOW_BUTTON_LABELS:
|
||||
self.hideRoomSeekLabels()
|
||||
self.hideMiscLabels()
|
||||
except ():
|
||||
self.updateReadyState(self.config['readyAtStart'])
|
||||
except:
|
||||
pass
|
||||
self.automaticUpdateCheck()
|
||||
|
||||
def promptFor(self, prompt=">", message=""):
|
||||
# TODO: Prompt user
|
||||
@ -93,7 +92,7 @@ class MainWindow(QtGui.QMainWindow):
|
||||
message = message.replace(">", "></span>")
|
||||
message = message.replace("\n", "<br />")
|
||||
if noTimestamp:
|
||||
self.newMessage(message + "<br />")
|
||||
self.newMessage("{}<br />".format(message))
|
||||
else:
|
||||
self.newMessage(time.strftime(constants.UI_TIME_FORMAT, time.localtime()) + message + "<br />")
|
||||
|
||||
@ -125,7 +124,13 @@ class MainWindow(QtGui.QMainWindow):
|
||||
for user in rooms[room]:
|
||||
useritem = QtGui.QStandardItem(user.username)
|
||||
isController = user.isController()
|
||||
sameRoom = room == currentUser.room
|
||||
if sameRoom:
|
||||
isReady = user.isReady()
|
||||
else:
|
||||
isReady = None
|
||||
useritem.setData(isController, Qt.UserRole + constants.USERITEM_CONTROLLER_ROLE)
|
||||
useritem.setData(isReady, Qt.UserRole + constants.USERITEM_READY_ROLE)
|
||||
if user.file:
|
||||
filesizeitem = QtGui.QStandardItem(formatSize(user.file['size']))
|
||||
filedurationitem = QtGui.QStandardItem("({})".format(formatTime(user.file['duration'])))
|
||||
@ -134,7 +139,6 @@ class MainWindow(QtGui.QMainWindow):
|
||||
sameName = sameFilename(user.file['name'], currentUser.file['name'])
|
||||
sameSize = sameFilesize(user.file['size'], currentUser.file['size'])
|
||||
sameDuration = sameFileduration(user.file['duration'], currentUser.file['duration'])
|
||||
sameRoom = room == currentUser.room
|
||||
underlinefont = QtGui.QFont()
|
||||
underlinefont.setUnderline(True)
|
||||
if sameRoom:
|
||||
@ -158,13 +162,14 @@ class MainWindow(QtGui.QMainWindow):
|
||||
font = QtGui.QFont()
|
||||
if currentUser.username == user.username:
|
||||
font.setWeight(QtGui.QFont.Bold)
|
||||
self.updateReadyState(currentUser.isReady())
|
||||
if isControlledRoom and not isController:
|
||||
useritem.setForeground(QtGui.QBrush(QtGui.QColor(constants.STYLE_NOTCONTROLLER_COLOR)))
|
||||
useritem.setFont(font)
|
||||
useritem.setFlags(useritem.flags() & ~Qt.ItemIsEditable)
|
||||
filenameitem.setFlags(filenameitem.flags() & ~Qt.ItemIsEditable)
|
||||
filesizeitem.setFlags(filesizeitem.flags() & ~Qt.ItemIsEditable)
|
||||
filedurationitem.setFlags(filedurationitem.flags() & ~Qt.ItemIsEditable)
|
||||
useritem.setFlags(useritem.flags() & ~Qt.ItemIsEditable & ~Qt.ItemIsSelectable)
|
||||
filenameitem.setFlags(filenameitem.flags() & ~Qt.ItemIsEditable & ~Qt.ItemIsSelectable)
|
||||
filesizeitem.setFlags(filesizeitem.flags() & ~Qt.ItemIsEditable & ~Qt.ItemIsSelectable)
|
||||
filedurationitem.setFlags(filedurationitem.flags() & ~Qt.ItemIsEditable & ~Qt.ItemIsSelectable)
|
||||
roomitem.appendRow((useritem, filesizeitem, filedurationitem, filenameitem))
|
||||
self.listTreeModel = self._usertreebuffer
|
||||
self.listTreeView.setModel(self.listTreeModel)
|
||||
@ -194,6 +199,14 @@ class MainWindow(QtGui.QMainWindow):
|
||||
except:
|
||||
pass
|
||||
|
||||
def updateReadyState(self, newState):
|
||||
oldState = self.readyPushButton.isChecked()
|
||||
if newState != oldState and newState != None:
|
||||
self.readyPushButton.blockSignals(True)
|
||||
self.readyPushButton.setChecked(newState)
|
||||
self.readyPushButton.blockSignals(False)
|
||||
self.updateReadyIcon()
|
||||
|
||||
def roomClicked(self, item):
|
||||
while item.parent().row() != -1:
|
||||
item = item.parent()
|
||||
@ -230,8 +243,18 @@ class MainWindow(QtGui.QMainWindow):
|
||||
self._syncplayClient.setRoom(room)
|
||||
self._syncplayClient.sendRoom()
|
||||
|
||||
def seekPosition(self):
|
||||
s = re.match(constants.UI_SEEK_REGEX, self.seekInput.text())
|
||||
def seekPositionDialog(self):
|
||||
seekTime, ok = QtGui.QInputDialog.getText(self, getMessage("seektime-menu-label"),
|
||||
getMessage("seektime-msgbox-label"), QtGui.QLineEdit.Normal,
|
||||
"0:00")
|
||||
if ok and seekTime != '':
|
||||
self.seekPosition(seekTime)
|
||||
|
||||
def seekFromButton(self):
|
||||
self.seekPosition(self.seekInput.text())
|
||||
|
||||
def seekPosition(self, seekTime):
|
||||
s = re.match(constants.UI_SEEK_REGEX, seekTime)
|
||||
if s:
|
||||
sign = self._extractSign(s.group('sign'))
|
||||
t = utils.parseTime(s.group('time'))
|
||||
@ -240,9 +263,8 @@ class MainWindow(QtGui.QMainWindow):
|
||||
if sign:
|
||||
t = self._syncplayClient.getGlobalPosition() + sign * t
|
||||
self._syncplayClient.setPosition(t)
|
||||
|
||||
else:
|
||||
self.showErrorMessage("Invalid seek value")
|
||||
self.showErrorMessage(getMessage("invalid-seek-value"))
|
||||
|
||||
def undoSeek(self):
|
||||
tmp_pos = self._syncplayClient.getPlayerPosition()
|
||||
@ -265,69 +287,6 @@ class MainWindow(QtGui.QMainWindow):
|
||||
self.exitSyncplay()
|
||||
self.saveSettings()
|
||||
|
||||
def setupSizes(self):
|
||||
self.hideRoomSeekLabels()
|
||||
self.miscThreshold = self.seekGroup.sizeHint().width()+self.roomGroup.sizeHint().width()+self.miscGroup.sizeHint().width()+30
|
||||
self.hideMiscLabels()
|
||||
self.setMinimumWidth(self.seekGroup.sizeHint().width()+self.roomGroup.sizeHint().width()+self.miscGroup.sizeHint().width()+30)
|
||||
self.seekGroup.setMinimumWidth(self.seekGroup.sizeHint().width())
|
||||
self.roomGroup.setMinimumWidth(self.roomGroup.sizeHint().width())
|
||||
self.miscGroup.setMinimumWidth(self.miscGroup.sizeHint().width())
|
||||
self.showRoomSeekLabels()
|
||||
self.showMiscLabels()
|
||||
windowMaximumWidth = self.maximumWidth()
|
||||
self.seekGroup.setMaximumWidth(self.seekGroup.sizeHint().width())
|
||||
self.roomGroup.setMaximumWidth(self.roomGroup.sizeHint().width())
|
||||
self.miscGroup.setMaximumWidth(self.miscGroup.sizeHint().width())
|
||||
self.setMaximumWidth(windowMaximumWidth)
|
||||
self.roomSeekThreshold = self.mainLayout.sizeHint().width()
|
||||
|
||||
def hideRoomSeekLabels(self):
|
||||
self.roomButton.setText("")
|
||||
self.seekButton.setText("")
|
||||
|
||||
def hideMiscLabels(self):
|
||||
self.unseekButton.setText("")
|
||||
if constants.MERGE_PLAYPAUSE_BUTTONS:
|
||||
self.playpauseButton.setText("")
|
||||
else:
|
||||
self.playButton.setText("")
|
||||
self.pauseButton.setText("")
|
||||
|
||||
def showRoomSeekLabels(self):
|
||||
if not constants.SHOW_BUTTON_LABELS:
|
||||
return
|
||||
self.roomButton.setText(getMessage("joinroom-guibuttonlabel"))
|
||||
self.seekButton.setText(getMessage("seektime-guibuttonlabel"))
|
||||
|
||||
def showMiscLabels(self):
|
||||
self.unseekButton.setText(getMessage("undoseek-guibuttonlabel"))
|
||||
if not constants.SHOW_BUTTON_LABELS:
|
||||
return
|
||||
if constants.MERGE_PLAYPAUSE_BUTTONS:
|
||||
self.playpauseButton.setText(getMessage("togglepause-guibuttonlabel"))
|
||||
else:
|
||||
self.playButton.setText(getMessage("play-guibuttonlabel"))
|
||||
self.pauseButton.setText(getMessage("pause-guibuttonlabel"))
|
||||
|
||||
def resizeEvent(self,resizeEvent):
|
||||
self.updateListGeometry()
|
||||
if self.roomGroup and self.miscThreshold:
|
||||
currentWidth = self.mainFrame.size().width()
|
||||
if currentWidth < self.miscThreshold:
|
||||
if self.unseekButton.text() != "":
|
||||
self.hideMiscLabels()
|
||||
else:
|
||||
if self.unseekButton.text() == "":
|
||||
self.showMiscLabels()
|
||||
|
||||
if currentWidth < self.roomSeekThreshold:
|
||||
if self.roomButton.text() != "":
|
||||
self.hideRoomSeekLabels()
|
||||
else:
|
||||
if self.roomButton.text() == "":
|
||||
self.showRoomSeekLabels()
|
||||
|
||||
def loadMediaBrowseSettings(self):
|
||||
settings = QSettings("Syncplay", "MediaBrowseDialog")
|
||||
settings.beginGroup("MediaBrowseDialog")
|
||||
@ -365,6 +324,13 @@ class MainWindow(QtGui.QMainWindow):
|
||||
self.saveMediaBrowseSettings()
|
||||
self._syncplayClient._player.openFile(fileName)
|
||||
|
||||
def promptForStreamURL(self):
|
||||
streamURL, ok = QtGui.QInputDialog.getText(self, getMessage("promptforstreamurl-msgbox-label"),
|
||||
getMessage("promptforstreamurlinfo-msgbox-label"), QtGui.QLineEdit.Normal,
|
||||
"")
|
||||
if ok and streamURL != '':
|
||||
self._syncplayClient._player.openFile(streamURL)
|
||||
|
||||
def createControlledRoom(self):
|
||||
controlroom, ok = QtGui.QInputDialog.getText(self, getMessage("createcontrolledroom-msgbox-label"),
|
||||
getMessage("controlledroominfo-msgbox-label"), QtGui.QLineEdit.Normal,
|
||||
@ -405,15 +371,15 @@ class MainWindow(QtGui.QMainWindow):
|
||||
t = self._syncplayClient.getUserOffset() + sign * t
|
||||
self._syncplayClient.setUserOffset(t)
|
||||
else:
|
||||
self.showErrorMessage("Invalid offset value")
|
||||
self.showErrorMessage(getMessage("invalid-offset-value"))
|
||||
|
||||
def openUserGuide(self):
|
||||
if sys.platform.startswith('linux'):
|
||||
self.QtGui.QDesktopServices.openUrl("http://syncplay.pl/guide/linux/")
|
||||
self.QtGui.QDesktopServices.openUrl(QUrl("http://syncplay.pl/guide/linux/"))
|
||||
elif sys.platform.startswith('win'):
|
||||
self.QtGui.QDesktopServices.openUrl("http://syncplay.pl/guide/windows/")
|
||||
self.QtGui.QDesktopServices.openUrl(QUrl("http://syncplay.pl/guide/windows/"))
|
||||
else:
|
||||
self.QtGui.QDesktopServices.openUrl("http://syncplay.pl/guide/")
|
||||
self.QtGui.QDesktopServices.openUrl(QUrl("http://syncplay.pl/guide/"))
|
||||
|
||||
def drop(self):
|
||||
self.close()
|
||||
@ -422,8 +388,16 @@ class MainWindow(QtGui.QMainWindow):
|
||||
window.topSplit = self.topSplitter(Qt.Horizontal, self)
|
||||
|
||||
window.outputLayout = QtGui.QVBoxLayout()
|
||||
window.outputbox = QtGui.QTextEdit()
|
||||
window.outputbox = QtGui.QTextBrowser()
|
||||
window.outputbox.setReadOnly(True)
|
||||
window.outputbox.setTextInteractionFlags(window.outputbox.textInteractionFlags() | Qt.TextSelectableByKeyboard)
|
||||
window.outputbox.setOpenExternalLinks(True)
|
||||
window.outputbox.unsetCursor()
|
||||
window.outputbox.moveCursor(QtGui.QTextCursor.End)
|
||||
window.outputbox.insertHtml(constants.STYLE_CONTACT_INFO.format(getMessage("contact-label")))
|
||||
window.outputbox.moveCursor(QtGui.QTextCursor.End)
|
||||
window.outputbox.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
|
||||
|
||||
window.outputlabel = QtGui.QLabel(getMessage("notifications-heading-label"))
|
||||
window.outputFrame = QtGui.QFrame()
|
||||
window.outputFrame.setLineWidth(0)
|
||||
@ -443,19 +417,28 @@ class MainWindow(QtGui.QMainWindow):
|
||||
window.listFrame = QtGui.QFrame()
|
||||
window.listFrame.setLineWidth(0)
|
||||
window.listFrame.setMidLineWidth(0)
|
||||
window.listFrame.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred)
|
||||
window.listLayout.setContentsMargins(0, 0, 0, 0)
|
||||
window.listLayout.addWidget(window.listlabel)
|
||||
window.listLayout.addWidget(window.listTreeView)
|
||||
window.contactLabel = QtGui.QLabel()
|
||||
window.contactLabel.setWordWrap(True)
|
||||
window.contactLabel.setFrameStyle(QtGui.QFrame.Box | QtGui.QFrame.Sunken)
|
||||
window.contactLabel.setLineWidth(1)
|
||||
window.contactLabel.setMidLineWidth(0)
|
||||
window.contactLabel.setMargin(2)
|
||||
window.contactLabel.setText(getMessage("contact-label"))
|
||||
window.contactLabel.setTextInteractionFlags(Qt.LinksAccessibleByMouse)
|
||||
window.contactLabel.setOpenExternalLinks(True)
|
||||
window.listLayout.addWidget(window.contactLabel)
|
||||
|
||||
window.roomInput = QtGui.QLineEdit()
|
||||
window.roomInput.returnPressed.connect(self.joinRoom)
|
||||
window.roomButton = QtGui.QPushButton(QtGui.QIcon(self.resourcespath + 'door_in.png'),
|
||||
getMessage("joinroom-menu-label"))
|
||||
window.roomButton.pressed.connect(self.joinRoom)
|
||||
window.roomLayout = QtGui.QHBoxLayout()
|
||||
window.roomFrame = QtGui.QFrame()
|
||||
window.roomFrame.setLayout(self.roomLayout)
|
||||
window.roomFrame.setContentsMargins(0,0,0,0)
|
||||
window.roomFrame.setSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Minimum)
|
||||
window.roomLayout.setContentsMargins(0,0,0,0)
|
||||
self.roomButton.setToolTip(getMessage("joinroom-tooltip"))
|
||||
window.roomLayout.addWidget(window.roomInput)
|
||||
window.roomLayout.addWidget(window.roomButton)
|
||||
window.roomFrame.setMaximumHeight(window.roomFrame.sizeHint().height())
|
||||
window.listLayout.addWidget(window.roomFrame, Qt.AlignRight)
|
||||
|
||||
window.listFrame.setLayout(window.listLayout)
|
||||
|
||||
window.topSplit.addWidget(window.outputFrame)
|
||||
@ -467,102 +450,106 @@ class MainWindow(QtGui.QMainWindow):
|
||||
|
||||
def addBottomLayout(self, window):
|
||||
window.bottomLayout = QtGui.QHBoxLayout()
|
||||
window.bottomFrame = QtGui.QFrame()
|
||||
window.bottomFrame.setLayout(window.bottomLayout)
|
||||
window.bottomLayout.setContentsMargins(0,0,0,0)
|
||||
|
||||
window.addRoomBox(MainWindow)
|
||||
window.addSeekBox(MainWindow)
|
||||
window.addMiscBox(MainWindow)
|
||||
self.addPlaybackLayout(window)
|
||||
|
||||
window.bottomLayout.addWidget(window.roomGroup)
|
||||
window.bottomLayout.addWidget(window.seekGroup)
|
||||
window.bottomLayout.addWidget(window.miscGroup)
|
||||
|
||||
window.mainLayout.addLayout(window.bottomLayout, Qt.AlignLeft)
|
||||
|
||||
def addRoomBox(self, window):
|
||||
window.roomGroup = QtGui.QGroupBox(getMessage("room-heading-label"))
|
||||
|
||||
window.roomInput = QtGui.QLineEdit()
|
||||
window.roomInput.returnPressed.connect(self.joinRoom)
|
||||
window.roomButton = QtGui.QPushButton(QtGui.QIcon(self.resourcespath + 'door_in.png'),
|
||||
getMessage("joinroom-guibuttonlabel"))
|
||||
window.roomButton.pressed.connect(self.joinRoom)
|
||||
window.roomLayout = QtGui.QHBoxLayout()
|
||||
window.roomInput.setFixedWidth(150)
|
||||
|
||||
self.roomButton.setToolTip(getMessage("joinroom-tooltip"))
|
||||
|
||||
window.roomLayout.addWidget(window.roomInput)
|
||||
window.roomLayout.addWidget(window.roomButton)
|
||||
|
||||
window.roomGroup.setLayout(window.roomLayout)
|
||||
window.roomGroup.setFixedHeight(window.roomGroup.sizeHint().height())
|
||||
|
||||
def addSeekBox(self, window):
|
||||
window.seekGroup = QtGui.QGroupBox(getMessage("seek-heading-label"))
|
||||
window.readyPushButton = QtGui.QPushButton()
|
||||
readyFont = QtGui.QFont()
|
||||
readyFont.setWeight(QtGui.QFont.Bold)
|
||||
window.readyPushButton.setText(getMessage("ready-guipushbuttonlabel"))
|
||||
window.readyPushButton.setCheckable(True)
|
||||
window.readyPushButton.setAutoExclusive(False)
|
||||
window.readyPushButton.toggled.connect(self.changeReadyState)
|
||||
window.readyPushButton.setFont(readyFont)
|
||||
window.readyPushButton.setStyleSheet(constants.STYLE_READY_PUSHBUTTON)
|
||||
window.listLayout.addWidget(window.readyPushButton, Qt.AlignRight)
|
||||
window.autoPlayPushButton = QtGui.QPushButton()
|
||||
window.autoPlayPushButton.setVisible(False)
|
||||
autoPlayFont = QtGui.QFont()
|
||||
autoPlayFont.setWeight(QtGui.QFont.Bold)
|
||||
window.autoPlayPushButton.setText(getMessage("autoplay-guipushbuttonlabel"))
|
||||
window.autoPlayPushButton.setCheckable(True)
|
||||
window.autoPlayPushButton.setAutoExclusive(False)
|
||||
window.autoPlayPushButton.toggled.connect(self.changeAutoPlayState)
|
||||
window.autoPlayPushButton.setFont(autoPlayFont)
|
||||
window.autoPlayPushButton.setStyleSheet(constants.STYLE_AUTO_PLAY_PUSHBUTTON)
|
||||
window.listLayout.addWidget(window.autoPlayPushButton, Qt.AlignRight)
|
||||
self.updateAutoPlayIcon()
|
||||
window.mainLayout.addWidget(window.bottomFrame, Qt.AlignLeft)
|
||||
window.bottomFrame.setMaximumHeight(window.bottomFrame.minimumSizeHint().height())
|
||||
|
||||
def addPlaybackLayout(self, window):
|
||||
window.playbackFrame = QtGui.QFrame()
|
||||
window.playbackFrame.setVisible(False)
|
||||
window.playbackFrame.setContentsMargins(0,0,0,0)
|
||||
window.playbackLayout = QtGui.QHBoxLayout()
|
||||
window.playbackLayout.setAlignment(Qt.AlignLeft)
|
||||
window.playbackLayout.setContentsMargins(0,0,0,0)
|
||||
window.playbackFrame.setLayout(window.playbackLayout)
|
||||
window.seekInput = QtGui.QLineEdit()
|
||||
window.seekInput.returnPressed.connect(self.seekPosition)
|
||||
window.seekButton = QtGui.QPushButton(QtGui.QIcon(self.resourcespath + 'clock_go.png'),
|
||||
getMessage("seektime-guibuttonlabel"))
|
||||
window.seekButton.pressed.connect(self.seekPosition)
|
||||
|
||||
self.seekButton.setToolTip(getMessage("seektime-tooltip"))
|
||||
|
||||
window.seekLayout = QtGui.QHBoxLayout()
|
||||
window.seekInput.returnPressed.connect(self.seekFromButton)
|
||||
window.seekButton = QtGui.QPushButton(QtGui.QIcon(self.resourcespath + 'clock_go.png'), "")
|
||||
window.seekButton.setToolTip(getMessage("seektime-menu-label"))
|
||||
window.seekButton.pressed.connect(self.seekFromButton)
|
||||
window.seekInput.setText("0:00")
|
||||
window.seekInput.setFixedWidth(60)
|
||||
|
||||
window.seekLayout.addWidget(window.seekInput)
|
||||
window.seekLayout.addWidget(window.seekButton)
|
||||
|
||||
window.seekGroup.setLayout(window.seekLayout)
|
||||
window.seekGroup.setFixedHeight(window.seekGroup.sizeHint().height())
|
||||
|
||||
def addMiscBox(self, window):
|
||||
window.miscGroup = QtGui.QGroupBox(getMessage("othercommands-heading-label"))
|
||||
|
||||
window.unseekButton = QtGui.QPushButton(QtGui.QIcon(self.resourcespath + 'arrow_undo.png'),
|
||||
getMessage("undoseek-guibuttonlabel"))
|
||||
window.playbackLayout.addWidget(window.seekInput)
|
||||
window.playbackLayout.addWidget(window.seekButton)
|
||||
window.unseekButton = QtGui.QPushButton(QtGui.QIcon(self.resourcespath + 'arrow_undo.png'), "")
|
||||
window.unseekButton.setToolTip(getMessage("undoseek-menu-label"))
|
||||
window.unseekButton.pressed.connect(self.undoSeek)
|
||||
self.unseekButton.setToolTip(getMessage("undoseek-tooltip"))
|
||||
|
||||
window.miscLayout = QtGui.QHBoxLayout()
|
||||
window.miscLayout.addWidget(window.unseekButton)
|
||||
if constants.MERGE_PLAYPAUSE_BUTTONS == True:
|
||||
window.playpauseButton = QtGui.QPushButton(QtGui.QIcon(self.resourcespath + 'control_pause_blue.png'),
|
||||
getMessage("togglepause-guibuttonlabel"))
|
||||
window.playpauseButton.pressed.connect(self.togglePause)
|
||||
window.miscLayout.addWidget(window.playpauseButton)
|
||||
self.playpauseButton.setToolTip(getMessage("togglepause-tooltip"))
|
||||
else:
|
||||
window.playButton = QtGui.QPushButton(QtGui.QIcon(self.resourcespath + 'control_play_blue.png'),
|
||||
getMessage("play-guibuttonlabel"))
|
||||
window.playButton.pressed.connect(self.play)
|
||||
window.miscLayout.addWidget(window.playButton)
|
||||
window.pauseButton = QtGui.QPushButton(QtGui.QIcon(self.resourcespath + 'control_pause_blue.png'),
|
||||
getMessage("pause-guibuttonlabel"))
|
||||
window.pauseButton.pressed.connect(self.pause)
|
||||
window.miscLayout.addWidget(window.pauseButton)
|
||||
self.playButton.setToolTip(getMessage("play-tooltip"))
|
||||
self.pauseButton.setToolTip(getMessage("pause-tooltip"))
|
||||
|
||||
window.miscGroup.setLayout(window.miscLayout)
|
||||
window.miscGroup.setFixedHeight(window.miscGroup.sizeHint().height())
|
||||
|
||||
window.playbackLayout.addWidget(window.unseekButton)
|
||||
window.playButton = QtGui.QPushButton(QtGui.QIcon(self.resourcespath + 'control_play_blue.png'), "")
|
||||
window.playButton.setToolTip(getMessage("play-menu-label"))
|
||||
window.playButton.pressed.connect(self.play)
|
||||
window.playbackLayout.addWidget(window.playButton)
|
||||
window.pauseButton = QtGui.QPushButton(QtGui.QIcon(self.resourcespath + 'control_pause_blue.png'), "")
|
||||
window.pauseButton.setToolTip(getMessage("pause-menu-label"))
|
||||
window.pauseButton.pressed.connect(self.pause)
|
||||
window.playbackLayout.addWidget(window.pauseButton)
|
||||
window.playbackFrame.setMaximumHeight(window.playbackFrame.sizeHint().height())
|
||||
window.playbackFrame.setMaximumWidth(window.playbackFrame.sizeHint().width())
|
||||
window.outputLayout.addWidget(window.playbackFrame)
|
||||
|
||||
def addMenubar(self, window):
|
||||
window.menuBar = QtGui.QMenuBar()
|
||||
|
||||
# File menu
|
||||
|
||||
window.fileMenu = QtGui.QMenu(getMessage("file-menu-label"), self)
|
||||
window.openAction = window.fileMenu.addAction(QtGui.QIcon(self.resourcespath + 'folder_explore.png'),
|
||||
getMessage("openmedia-menu-label"))
|
||||
window.openAction.triggered.connect(self.browseMediapath)
|
||||
window.openAction = window.fileMenu.addAction(QtGui.QIcon(self.resourcespath + 'world_explore.png'),
|
||||
getMessage("openstreamurl-menu-label"))
|
||||
window.openAction.triggered.connect(self.promptForStreamURL)
|
||||
|
||||
window.exitAction = window.fileMenu.addAction(QtGui.QIcon(self.resourcespath + 'cross.png'),
|
||||
getMessage("exit-menu-label"))
|
||||
window.exitAction.triggered.connect(self.exitSyncplay)
|
||||
window.menuBar.addMenu(window.fileMenu)
|
||||
|
||||
# Playback menu
|
||||
|
||||
window.playbackMenu = QtGui.QMenu(getMessage("playback-menu-label"), self)
|
||||
window.playAction = window.playbackMenu.addAction(QtGui.QIcon(self.resourcespath + 'control_play_blue.png'), getMessage("play-menu-label"))
|
||||
window.playAction.triggered.connect(self.play)
|
||||
window.pauseAction = window.playbackMenu.addAction(QtGui.QIcon(self.resourcespath + 'control_pause_blue.png'), getMessage("pause-menu-label"))
|
||||
window.pauseAction.triggered.connect(self.pause)
|
||||
window.seekAction = window.playbackMenu.addAction(QtGui.QIcon(self.resourcespath + 'clock_go.png'), getMessage("seektime-menu-label"))
|
||||
window.seekAction.triggered.connect(self.seekPositionDialog)
|
||||
window.unseekAction = window.playbackMenu.addAction(QtGui.QIcon(self.resourcespath + 'arrow_undo.png'), getMessage("undoseek-menu-label"))
|
||||
window.unseekAction.triggered.connect(self.undoSeek)
|
||||
|
||||
window.menuBar.addMenu(window.playbackMenu)
|
||||
|
||||
# Advanced menu
|
||||
|
||||
window.advancedMenu = QtGui.QMenu(getMessage("advanced-menu-label"), self)
|
||||
window.setoffsetAction = window.advancedMenu.addAction(QtGui.QIcon(self.resourcespath + 'timeline_marker.png'),
|
||||
getMessage("setoffset-menu-label"))
|
||||
@ -574,12 +561,32 @@ class MainWindow(QtGui.QMainWindow):
|
||||
window.identifyascontroller = window.advancedMenu.addAction(QtGui.QIcon(self.resourcespath + 'key_go.png'),
|
||||
getMessage("identifyascontroller-menu-label"))
|
||||
window.identifyascontroller.triggered.connect(self.identifyAsController)
|
||||
|
||||
window.menuBar.addMenu(window.advancedMenu)
|
||||
|
||||
# Window menu
|
||||
|
||||
window.windowMenu = QtGui.QMenu(getMessage("window-menu-label"), self)
|
||||
|
||||
window.playbackAction = window.windowMenu.addAction(getMessage("playbackbuttons-menu-label"))
|
||||
window.playbackAction.setCheckable(True)
|
||||
window.playbackAction.triggered.connect(self.updatePlaybackFrameVisibility)
|
||||
|
||||
window.autoplayAction = window.windowMenu.addAction(getMessage("autoplay-menu-label"))
|
||||
window.autoplayAction.setCheckable(True)
|
||||
window.autoplayAction.triggered.connect(self.updateAutoplayVisibility)
|
||||
window.menuBar.addMenu(window.windowMenu)
|
||||
|
||||
|
||||
# Help menu
|
||||
|
||||
window.helpMenu = QtGui.QMenu(getMessage("help-menu-label"), self)
|
||||
window.userguideAction = window.helpMenu.addAction(QtGui.QIcon(self.resourcespath + 'help.png'),
|
||||
getMessage("userguide-menu-label"))
|
||||
window.userguideAction.triggered.connect(self.openUserGuide)
|
||||
window.updateAction = window.helpMenu.addAction(QtGui.QIcon(self.resourcespath + 'application_get.png'),
|
||||
getMessage("update-menu-label"))
|
||||
window.updateAction.triggered.connect(self.userCheckForUpdates)
|
||||
|
||||
window.menuBar.addMenu(window.helpMenu)
|
||||
window.mainLayout.setMenuBar(window.menuBar)
|
||||
@ -606,6 +613,81 @@ class MainWindow(QtGui.QMainWindow):
|
||||
self.listbox.insertHtml(item)
|
||||
self.listbox.moveCursor(QtGui.QTextCursor.End)
|
||||
|
||||
def updatePlaybackFrameVisibility(self):
|
||||
self.playbackFrame.setVisible(self.playbackAction.isChecked())
|
||||
|
||||
def updateAutoplayVisibility(self):
|
||||
self.autoPlayPushButton.setVisible(self.autoplayAction.isChecked())
|
||||
|
||||
def changeReadyState(self):
|
||||
self.updateReadyIcon()
|
||||
self._syncplayClient.changeReadyState(self.readyPushButton.isChecked())
|
||||
|
||||
def updateAutoPlayState(self, newState):
|
||||
oldState = self.autoPlayPushButton.isChecked()
|
||||
if newState != oldState and newState != None:
|
||||
self.autoPlayPushButton.setChecked(newState)
|
||||
self.updateAutoPlayIcon()
|
||||
|
||||
def changeAutoPlayState(self):
|
||||
self.updateAutoPlayIcon()
|
||||
self._syncplayClient.changeAutoPlayState(self.autoPlayPushButton.isChecked())
|
||||
|
||||
def updateReadyIcon(self):
|
||||
ready = self.readyPushButton.isChecked()
|
||||
if ready:
|
||||
self.readyPushButton.setIcon(QtGui.QIcon(self.resourcespath + 'tick_checkbox.png'))
|
||||
else:
|
||||
self.readyPushButton.setIcon(QtGui.QIcon(self.resourcespath + 'empty_checkbox.png'))
|
||||
|
||||
def updateAutoPlayIcon(self):
|
||||
ready = self.autoPlayPushButton.isChecked()
|
||||
if ready:
|
||||
self.autoPlayPushButton.setIcon(QtGui.QIcon(self.resourcespath + 'tick_checkbox.png'))
|
||||
else:
|
||||
self.autoPlayPushButton.setIcon(QtGui.QIcon(self.resourcespath + 'empty_checkbox.png'))
|
||||
|
||||
def automaticUpdateCheck(self):
|
||||
currentDateTime = datetime.utcnow()
|
||||
if not self.config['checkForUpdatesAutomatically']:
|
||||
return
|
||||
if self.config['lastCheckedForUpdates']:
|
||||
configLastChecked = datetime.strptime(self.config["lastCheckedForUpdates"], "%Y-%m-%d %H:%M:%S.%f")
|
||||
if self.lastCheckedForUpdates is None or configLastChecked > self.lastCheckedForUpdates:
|
||||
self.lastCheckedForUpdates = configLastChecked
|
||||
if self.lastCheckedForUpdates is None:
|
||||
self.checkForUpdates()
|
||||
else:
|
||||
timeDelta = currentDateTime - self.lastCheckedForUpdates
|
||||
if timeDelta.total_seconds() > constants.AUTOMATIC_UPDATE_CHECK_FREQUENCY:
|
||||
self.checkForUpdates()
|
||||
|
||||
def userCheckForUpdates(self):
|
||||
self.checkForUpdates(userInitiated=True)
|
||||
|
||||
def checkForUpdates(self, userInitiated=False):
|
||||
self.lastCheckedForUpdates = datetime.utcnow()
|
||||
updateStatus, updateMessage, updateURL = self._syncplayClient.checkForUpdate(userInitiated)
|
||||
if updateMessage is None:
|
||||
if updateStatus == "uptodate":
|
||||
updateMessage = getMessage("syncplay-uptodate-notification")
|
||||
elif updateStatus == "updateavailale":
|
||||
updateMessage = getMessage("syncplay-updateavailable-notification")
|
||||
else:
|
||||
import syncplay
|
||||
updateMessage = getMessage("update-check-failed-notification").format(syncplay.version)
|
||||
if userInitiated == True:
|
||||
updateURL = constants.SYNCPLAY_DOWNLOAD_URL
|
||||
if updateURL is not None:
|
||||
reply = QtGui.QMessageBox.question(self, "Syncplay",
|
||||
updateMessage, QtGui.QMessageBox.StandardButton.Yes | QtGui.QMessageBox.StandardButton.No)
|
||||
if reply == QtGui.QMessageBox.Yes:
|
||||
self.QtGui.QDesktopServices.openUrl(QUrl(updateURL))
|
||||
elif userInitiated:
|
||||
QtGui.QMessageBox.information(self, "Syncplay", updateMessage)
|
||||
else:
|
||||
self.showMessage(updateMessage)
|
||||
|
||||
def dragEnterEvent(self, event):
|
||||
data = event.mimeData()
|
||||
urls = data.urls()
|
||||
@ -633,6 +715,12 @@ class MainWindow(QtGui.QMainWindow):
|
||||
settings.beginGroup("MainWindow")
|
||||
settings.setValue("size", self.size())
|
||||
settings.setValue("pos", self.pos())
|
||||
settings.setValue("showPlaybackButtons", self.playbackAction.isChecked())
|
||||
settings.setValue("showAutoPlayButton", self.autoplayAction.isChecked())
|
||||
settings.endGroup()
|
||||
settings = QSettings("Syncplay", "Interface")
|
||||
settings.beginGroup("Update")
|
||||
settings.setValue("lastChecked", self.lastCheckedForUpdates)
|
||||
settings.endGroup()
|
||||
|
||||
def loadSettings(self):
|
||||
@ -640,7 +728,16 @@ class MainWindow(QtGui.QMainWindow):
|
||||
settings.beginGroup("MainWindow")
|
||||
self.resize(settings.value("size", QSize(700, 500)))
|
||||
self.move(settings.value("pos", QPoint(200, 200)))
|
||||
if settings.value("showPlaybackButtons", "false") == "true":
|
||||
self.playbackAction.setChecked(True)
|
||||
self.updatePlaybackFrameVisibility()
|
||||
if settings.value("showAutoPlayButton", "false") == "true":
|
||||
self.autoplayAction.setChecked(True)
|
||||
self.updateAutoplayVisibility()
|
||||
settings.endGroup()
|
||||
settings = QSettings("Syncplay", "Interface")
|
||||
settings.beginGroup("Update")
|
||||
self.lastCheckedForUpdates = settings.value("lastChecked", None)
|
||||
|
||||
def __init__(self):
|
||||
super(MainWindow, self).__init__()
|
||||
@ -656,7 +753,6 @@ class MainWindow(QtGui.QMainWindow):
|
||||
self.addBottomLayout(self)
|
||||
self.addMenubar(self)
|
||||
self.addMainFrame(self)
|
||||
self.setupSizes()
|
||||
self.loadSettings()
|
||||
self.setWindowIcon(QtGui.QIcon(self.resourcespath + "syncplay.png"))
|
||||
self.setWindowFlags(self.windowFlags() & Qt.WindowCloseButtonHint & Qt.AA_DontUseNativeMenuBar & Qt.WindowMinimizeButtonHint & ~Qt.WindowContextHelpButtonHint)
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python2
|
||||
|
||||
import site, sys
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python2
|
||||
#coding:utf8
|
||||
|
||||
import site, sys
|
||||
@ -20,5 +20,5 @@ if __name__ == '__main__':
|
||||
argsGetter = ConfigurationGetter()
|
||||
args = argsGetter.getConfiguration()
|
||||
|
||||
reactor.listenTCP(int(args.port), SyncFactory(args.password, args.motd_file, args.isolate_rooms, args.salt))
|
||||
reactor.listenTCP(int(args.port), SyncFactory(args.password, args.motd_file, args.isolate_rooms, args.salt, args.disable_ready))
|
||||
reactor.run()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user