Add secondaryOSD (w/ VLC support & fallback code), re-work warnings, fix misc. VLC bugs, allow longer offsets
This commit is contained in:
parent
23cf1afd5a
commit
3ff43473eb
@ -5,7 +5,7 @@
|
|||||||
Principal author: Etoh
|
Principal author: Etoh
|
||||||
Other contributors: DerGenaue, jb
|
Other contributors: DerGenaue, jb
|
||||||
Project: http://syncplay.pl/
|
Project: http://syncplay.pl/
|
||||||
Version: 0.2.3
|
Version: 0.2.4
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
* This interface module is intended to be used in conjunction with Syncplay.
|
* 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: [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-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: [filepath]
|
||||||
* >> load-file-attempted
|
* >> 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 durationdelay = 500000 -- Pause for get_duration command etc for increased reliability (uses microseconds)
|
||||||
local loopsleepduration = 5000 -- Pause for every event loop (uses microseconds)
|
local loopsleepduration = 5000 -- Pause for every event loop (uses microseconds)
|
||||||
local quitcheckfrequency = 20 -- Check whether VLC has closed every X loops
|
local quitcheckfrequency = 20 -- Check whether VLC has closed every X loops
|
||||||
@ -108,12 +111,18 @@ local newinputstate
|
|||||||
local oldtitle = 0
|
local oldtitle = 0
|
||||||
local newtitle = 0
|
local newtitle = 0
|
||||||
|
|
||||||
|
local channel1
|
||||||
|
local channel2
|
||||||
|
local l
|
||||||
|
|
||||||
local running = true
|
local running = true
|
||||||
|
|
||||||
|
|
||||||
function radixsafe_tonumber(str)
|
function radixsafe_tonumber(str)
|
||||||
-- Version of tonumber that works with any radix character (but not thousand seperators)
|
-- Version of tonumber that works with any radix character (but not thousand seperators)
|
||||||
-- Based on the public domain VLC common.lua us_tonumber() function
|
-- 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*)$")
|
local s, i, d = string.match(str, "^([+-]?)(%d*)%.?(%d*)$")
|
||||||
if not s or not i or not d then
|
if not s or not i or not d then
|
||||||
return nil
|
return nil
|
||||||
@ -277,8 +286,8 @@ function set_time ( timetoset)
|
|||||||
end
|
end
|
||||||
errormsg = set_var("time", radixsafe_tonumber(realtime))
|
errormsg = set_var("time", radixsafe_tonumber(realtime))
|
||||||
return errormsg
|
return errormsg
|
||||||
else
|
else
|
||||||
return noinput
|
return noinput
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -379,17 +388,19 @@ function get_duration ()
|
|||||||
|
|
||||||
if input then
|
if input then
|
||||||
local item = vlc.input.item()
|
local item = vlc.input.item()
|
||||||
if (item and item:duration()) then
|
|
||||||
-- Try to get duration, which might not be available straight away
|
-- Try to get duration, which might not be available straight away
|
||||||
local i = 0
|
local i = 0
|
||||||
repeat
|
response = 0
|
||||||
vlc.misc.mwait(vlc.misc.mdate() + durationdelay)
|
repeat
|
||||||
|
vlc.misc.mwait(vlc.misc.mdate() + durationdelay)
|
||||||
|
if item and item:duration() then
|
||||||
response = item:duration()
|
response = item:duration()
|
||||||
i = i + 1
|
if response < 1 then
|
||||||
until response > 0 or i > 5
|
response = 0
|
||||||
else
|
end
|
||||||
errormsg = noinput
|
end
|
||||||
end
|
i = i + 1
|
||||||
|
until response > 1 or i > 5
|
||||||
else
|
else
|
||||||
errormsg = noinput
|
errormsg = noinput
|
||||||
end
|
end
|
||||||
@ -400,11 +411,16 @@ end
|
|||||||
|
|
||||||
function display_osd ( argument )
|
function display_osd ( argument )
|
||||||
-- [Used by display-osd command]
|
-- [Used by display-osd command]
|
||||||
|
|
||||||
local errormsg
|
local errormsg
|
||||||
local osdarray
|
local osdarray
|
||||||
local input = vlc.object.input()
|
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)
|
osdarray = get_args(argument,3)
|
||||||
--position, duration, message -> message, , position, duration (converted from seconds to microseconds)
|
--position, duration, message -> message, , position, duration (converted from seconds to microseconds)
|
||||||
local osdduration = radixsafe_tonumber(osdarray[2]) * 1000 * 1000
|
local osdduration = radixsafe_tonumber(osdarray[2]) * 1000 * 1000
|
||||||
@ -415,6 +431,28 @@ function display_osd ( argument )
|
|||||||
return errormsg
|
return errormsg
|
||||||
end
|
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)
|
function load_file (filepath)
|
||||||
-- [Used by load-file command]
|
-- [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-rate" then errormsg = set_var("rate", radixsafe_tonumber(argument))
|
||||||
elseif command == "set-title" then errormsg = set_var("title", 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-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 == "load-file" then response = load_file(argument)
|
||||||
elseif command == "close-vlc" then quit_vlc()
|
elseif command == "close-vlc" then quit_vlc()
|
||||||
else errormsg = unknowncommand
|
else errormsg = unknowncommand
|
||||||
@ -498,7 +537,7 @@ while running == true do
|
|||||||
--accept new connections and select active clients
|
--accept new connections and select active clients
|
||||||
local quitcheckcounter = 0
|
local quitcheckcounter = 0
|
||||||
local fd = l:accept()
|
local fd = l:accept()
|
||||||
local buffer, inputbuffer, responsebuffer = ""
|
local buffer, inputbuffer, responsebuffer = "", "", ""
|
||||||
while fd >= 0 and running == true do
|
while fd >= 0 and running == true do
|
||||||
|
|
||||||
-- handle read mode
|
-- handle read mode
|
||||||
@ -560,7 +599,6 @@ while running == true do
|
|||||||
quitcheckcounter = 0
|
quitcheckcounter = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@ -106,7 +106,7 @@ class SyncplayClient(object):
|
|||||||
self._speedChanged = False
|
self._speedChanged = False
|
||||||
self.behindFirstDetected = None
|
self.behindFirstDetected = None
|
||||||
|
|
||||||
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']:
|
if constants.LIST_RELATIVE_CONFIGS and self._config.has_key('loadedRelativePaths') and self._config['loadedRelativePaths']:
|
||||||
paths = "; ".join(self._config['loadedRelativePaths'])
|
paths = "; ".join(self._config['loadedRelativePaths'])
|
||||||
self.ui.showMessage(getMessage("relative-config-notification").format(paths), noPlayer=True, noTimestamp=True)
|
self.ui.showMessage(getMessage("relative-config-notification").format(paths), noPlayer=True, noTimestamp=True)
|
||||||
@ -126,6 +126,8 @@ class SyncplayClient(object):
|
|||||||
|
|
||||||
def initPlayer(self, player):
|
def initPlayer(self, player):
|
||||||
self._player = player
|
self._player = player
|
||||||
|
if not self._player.secondaryOSDSupported:
|
||||||
|
constants.OSD_WARNING_MESSAGE_DURATION = constants.NO_SECONDARY_OSD_WARNING_DURATION
|
||||||
self.scheduleAskPlayer()
|
self.scheduleAskPlayer()
|
||||||
|
|
||||||
def scheduleAskPlayer(self, when=constants.PLAYER_ASK_DELAY):
|
def scheduleAskPlayer(self, when=constants.PLAYER_ASK_DELAY):
|
||||||
@ -496,17 +498,20 @@ class SyncplayClient(object):
|
|||||||
oldReadyState = False
|
oldReadyState = False
|
||||||
self.userlist.setReady(username, isReady)
|
self.userlist.setReady(username, isReady)
|
||||||
self.ui.userListChange()
|
self.ui.userListChange()
|
||||||
if manuallyInitiated and oldReadyState != isReady:
|
if oldReadyState != isReady:
|
||||||
showOnOSD = constants.SHOW_OSD_WARNINGS
|
self._warnings.checkReadyStates()
|
||||||
if constants.SHOW_NONCONTROLLER_OSD == False and self.userlist.canControl(username) == False and self.userlist.currentUser.isController() == False:
|
if manuallyInitiated:
|
||||||
# Ignore SHOW_NONCONTROLLER_OSD setting if user is controller, because they need to know who is/isn't ready
|
showOnOSD = constants.SHOW_OSD_WARNINGS
|
||||||
showOnOSD = False
|
if constants.SHOW_NONCONTROLLER_OSD == False and self.userlist.canControl(username) == False and self.userlist.currentUser.isController() == False:
|
||||||
hideFromOSD = not showOnOSD
|
# Ignore SHOW_NONCONTROLLER_OSD setting if user is controller, because they need to know who is/isn't ready
|
||||||
if isReady:
|
showOnOSD = False
|
||||||
message = getMessage("user-ready-notification").format(username)
|
hideFromOSD = not showOnOSD
|
||||||
else:
|
if isReady:
|
||||||
message = getMessage("user-not-ready-notification").format(username)
|
message = getMessage("user-ready-notification").format(username)
|
||||||
self.ui.showMessage(message, hideFromOSD)
|
else:
|
||||||
|
message = getMessage("user-not-ready-notification").format(username)
|
||||||
|
self.ui.showMessage(message, hideFromOSD, False)
|
||||||
|
|
||||||
|
|
||||||
@requireMinServerVersion(constants.CONTROLLED_ROOMS_MIN_VERSION)
|
@requireMinServerVersion(constants.CONTROLLED_ROOMS_MIN_VERSION)
|
||||||
def createControlledRoom(self, roomName):
|
def createControlledRoom(self, roomName):
|
||||||
@ -556,51 +561,107 @@ class SyncplayClient(object):
|
|||||||
return self.controlpasswords[room]
|
return self.controlpasswords[room]
|
||||||
|
|
||||||
class _WarningManager(object):
|
class _WarningManager(object):
|
||||||
def __init__(self, player, userlist, ui):
|
def __init__(self, player, userlist, ui, client):
|
||||||
|
self._client = client
|
||||||
self._player = player
|
self._player = player
|
||||||
self._userlist = userlist
|
self._userlist = userlist
|
||||||
self._ui = ui
|
self._ui = ui
|
||||||
self._warnings = {
|
self._warnings = {
|
||||||
"room-files-not-same": {
|
"room-files-not-same": {
|
||||||
"timer": task.LoopingCall(self.__displayMessageOnOSD,
|
"timer": task.LoopingCall(self.__displayMessageOnOSD, "room-files-not-same",
|
||||||
"room-files-not-same", ),
|
lambda: self._checkRoomForSameFiles(OSDOnly=True),),
|
||||||
"displayedFor": 0,
|
"displayedFor": 0,
|
||||||
},
|
},
|
||||||
"alone-in-the-room": {
|
"alone-in-the-room": {
|
||||||
"timer": task.LoopingCall(self.__displayMessageOnOSD,
|
"timer": task.LoopingCall(self.__displayMessageOnOSD, "alone-in-the-room",
|
||||||
"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,
|
"displayedFor": 0,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
def checkWarnings(self):
|
self.pausedTimer = task.LoopingCall(self.__displayPausedMessagesOnOSD)
|
||||||
self._checkIfYouReAloneInTheRoom()
|
self.pausedTimer.start(constants.WARNING_OSD_MESSAGES_LOOP_INTERVAL, True)
|
||||||
self._checkRoomForSameFiles()
|
|
||||||
|
|
||||||
def _checkRoomForSameFiles(self):
|
def checkWarnings(self):
|
||||||
|
self._checkIfYouReAloneInTheRoom(OSDOnly=False)
|
||||||
|
self._checkRoomForSameFiles(OSDOnly=False)
|
||||||
|
self.checkReadyStates()
|
||||||
|
|
||||||
|
def _checkRoomForSameFiles(self, OSDOnly):
|
||||||
if not self._userlist.areAllFilesInRoomSame():
|
if not self._userlist.areAllFilesInRoomSame():
|
||||||
self._ui.showMessage(getMessage("room-files-not-same"), True)
|
self._displayReadySameWarning()
|
||||||
if constants.SHOW_OSD_WARNINGS and not self._warnings["room-files-not-same"]['timer'].running:
|
if not OSDOnly:
|
||||||
self._warnings["room-files-not-same"]['timer'].start(constants.WARNING_OSD_MESSAGES_LOOP_INTERVAL, True)
|
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:
|
elif self._warnings["room-files-not-same"]['timer'].running:
|
||||||
self._warnings["room-files-not-same"]['timer'].stop()
|
self._warnings["room-files-not-same"]['timer'].stop()
|
||||||
|
|
||||||
def _checkIfYouReAloneInTheRoom(self):
|
def _checkIfYouReAloneInTheRoom(self, OSDOnly):
|
||||||
if self._userlist.areYouAloneInRoom():
|
if self._userlist.areYouAloneInRoom():
|
||||||
self._ui.showMessage(getMessage("alone-in-the-room"), True)
|
self._ui.showOSDMessage(getMessage("alone-in-the-room"), constants.WARNING_OSD_MESSAGES_LOOP_INTERVAL, secondaryOSD=True)
|
||||||
if constants.SHOW_OSD_WARNINGS and not self._warnings["alone-in-the-room"]['timer'].running:
|
if not OSDOnly:
|
||||||
self._warnings["alone-in-the-room"]['timer'].start(constants.WARNING_OSD_MESSAGES_LOOP_INTERVAL, True)
|
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:
|
elif self._warnings["alone-in-the-room"]['timer'].running:
|
||||||
self._warnings["alone-in-the-room"]['timer'].stop()
|
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._userlist.areAllFilesInRoomSame():
|
||||||
|
if self._userlist.currentUser.canControl():
|
||||||
|
if self._userlist.areAllUsersInRoomReady():
|
||||||
|
osdMessage = u"{}; {}".format(getMessage("room-files-not-same"), getMessage("all-users-ready"))
|
||||||
|
else:
|
||||||
|
osdMessage = u"{}; {}".format(getMessage("room-files-not-same"), getMessage("not-all-ready").format(self._userlist.usersInRoomNotReady()))
|
||||||
|
else:
|
||||||
|
osdMessage = getMessage("room-files-not-same")
|
||||||
|
elif self._userlist.areAllUsersInRoomReady():
|
||||||
|
osdMessage = getMessage("all-users-ready")
|
||||||
|
else:
|
||||||
|
osdMessage = getMessage("not-all-ready").format(self._userlist.usersInRoomNotReady())
|
||||||
|
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"]:
|
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
|
self._warnings[warningName]["displayedFor"] += constants.WARNING_OSD_MESSAGES_LOOP_INTERVAL
|
||||||
else:
|
else:
|
||||||
self._warnings[warningName]["displayedFor"] = 0
|
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._player.secondaryOSDSupported and self._userlist.currentUser.file 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):
|
class SyncplayUser(object):
|
||||||
def __init__(self, username=None, room=None, file_=None):
|
def __init__(self, username=None, room=None, file_=None):
|
||||||
@ -764,11 +825,31 @@ class SyncplayUserlist(object):
|
|||||||
user = self._users[username]
|
user = self._users[username]
|
||||||
user.setControllerStatus(True)
|
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():
|
for user in self._users.itervalues():
|
||||||
if user.room == self.currentUser.room and user.file and not self.currentUser.isFileSame(user.file):
|
if user.room == self.currentUser.room and user.isReady() == False:
|
||||||
if user.canControl():
|
return False
|
||||||
return False
|
return True
|
||||||
|
|
||||||
|
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
|
return True
|
||||||
|
|
||||||
def areYouAloneInRoom(self):
|
def areYouAloneInRoom(self):
|
||||||
@ -843,22 +924,38 @@ class UiManager(object):
|
|||||||
def __init__(self, client, ui):
|
def __init__(self, client, ui):
|
||||||
self._client = client
|
self._client = client
|
||||||
self.__ui = ui
|
self.__ui = ui
|
||||||
|
self.lastPrimaryOSDMessage = None
|
||||||
|
self.lastPrimaryOSDEndTime = None
|
||||||
|
self.lastSecondaryOSDMessage = None
|
||||||
|
self.lastSecondaryOSDEndTime = None
|
||||||
self.lastError = ""
|
self.lastError = ""
|
||||||
|
|
||||||
def showDebugMessage(self, message):
|
def showDebugMessage(self, message):
|
||||||
if constants.DEBUG_MODE and message.rstrip():
|
if constants.DEBUG_MODE and message.rstrip():
|
||||||
print "{}{}".format(time.strftime(constants.UI_TIME_FORMAT, time.localtime()),message.rstrip())
|
print "{}{}".format(time.strftime(constants.UI_TIME_FORMAT, time.localtime()),message.rstrip())
|
||||||
|
|
||||||
def showMessage(self, message, noPlayer=False, noTimestamp=False):
|
def showMessage(self, message, noPlayer=False, noTimestamp=False, secondaryOSD=False):
|
||||||
if not noPlayer: self.showOSDMessage(message)
|
if not noPlayer: self.showOSDMessage(message, duration=constants.OSD_DURATION, secondaryOSD=secondaryOSD)
|
||||||
self.__ui.showMessage(message, noTimestamp)
|
self.__ui.showMessage(message, noTimestamp)
|
||||||
|
|
||||||
def showUserList(self, currentUser, rooms):
|
def showUserList(self, currentUser, rooms):
|
||||||
self.__ui.showUserList(currentUser, rooms)
|
self.__ui.showUserList(currentUser, rooms)
|
||||||
|
|
||||||
def showOSDMessage(self, message, duration=constants.OSD_DURATION):
|
def showOSDMessage(self, message, duration=constants.OSD_DURATION, secondaryOSD=False):
|
||||||
if constants.SHOW_OSD and self._client._player:
|
if constants.SHOW_OSD and self._client and self._client._player:
|
||||||
self._client._player.displayMessage(message, duration * 1000)
|
if not self._client._player.secondaryOSDSupported:
|
||||||
|
if secondaryOSD:
|
||||||
|
message = u"({})".format(message)
|
||||||
|
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.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, message)
|
||||||
|
self._client._player.displayMessage(message, duration * 1000, secondaryOSD)
|
||||||
|
|
||||||
def setControllerStatus(self, username, isController):
|
def setControllerStatus(self, username, isController):
|
||||||
self.__ui.setControllerStatus(username, isController)
|
self.__ui.setControllerStatus(username, isController)
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
# You might want to change these
|
# You might want to change these
|
||||||
DEFAULT_PORT = 8999
|
DEFAULT_PORT = 8999
|
||||||
OSD_DURATION = 3
|
OSD_DURATION = 3
|
||||||
OSD_WARNING_MESSAGE_DURATION = 15
|
OSD_WARNING_MESSAGE_DURATION = 5
|
||||||
|
NO_SECONDARY_OSD_WARNING_DURATION = 15
|
||||||
MPC_OSD_POSITION = 2 #Right corner, 1 for left
|
MPC_OSD_POSITION = 2 #Right corner, 1 for left
|
||||||
MPLAYER_OSD_LEVEL = 1
|
MPLAYER_OSD_LEVEL = 1
|
||||||
UI_TIME_FORMAT = "[%X] "
|
UI_TIME_FORMAT = "[%X] "
|
||||||
@ -62,7 +63,7 @@ COMMANDS_AUTH = ['a','auth']
|
|||||||
COMMANDS_READY = ['re']
|
COMMANDS_READY = ['re']
|
||||||
MPC_MIN_VER = "1.6.4"
|
MPC_MIN_VER = "1.6.4"
|
||||||
VLC_MIN_VERSION = "2.0.0"
|
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"
|
CONTROLLED_ROOMS_MIN_VERSION = "1.3.0"
|
||||||
USER_READY_MIN_VERSION = "1.3.1"
|
USER_READY_MIN_VERSION = "1.3.1"
|
||||||
MPC_PATHS = [
|
MPC_PATHS = [
|
||||||
@ -141,7 +142,7 @@ VLC_SLAVE_NONOSX_ARGS = ['--no-one-instance', '--no-one-instance-when-started-fr
|
|||||||
MPLAYER_ANSWER_REGEX = "^ANS_([a-zA-Z_-]+)=(.+)$|^(Exiting)\.\.\. \((.+)\)$"
|
MPLAYER_ANSWER_REGEX = "^ANS_([a-zA-Z_-]+)=(.+)$|^(Exiting)\.\.\. \((.+)\)$"
|
||||||
VLC_ANSWER_REGEX = r"(?:^(?P<command>[a-zA-Z_]+)(?:\: )?(?P<argument>.*))"
|
VLC_ANSWER_REGEX = r"(?:^(?P<command>[a-zA-Z_]+)(?:\: )?(?P<argument>.*))"
|
||||||
UI_COMMAND_REGEX = r"^(?P<command>[^\ ]+)(?:\ (?P<parameter>.+))?"
|
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}))?)$"
|
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+?))?$'
|
PARSE_TIME_REGEX = r'(:?(?:(?P<hours>\d+?)[^\d\.])?(?:(?P<minutes>\d+?))?[^\d\.])?(?P<seconds>\d+?)(?:\.(?P<miliseconds>\d+?))?$'
|
||||||
SERVER_MAX_TEMPLATE_LENGTH = 10000
|
SERVER_MAX_TEMPLATE_LENGTH = 10000
|
||||||
|
|||||||
@ -35,6 +35,8 @@ en = {
|
|||||||
|
|
||||||
"user-ready-notification" : "<{}> I'm ready", # Username
|
"user-ready-notification" : "<{}> I'm ready", # Username
|
||||||
"user-not-ready-notification" : "<{}> I'm not ready", # Username
|
"user-not-ready-notification" : "<{}> I'm not ready", # Username
|
||||||
|
"not-all-ready" : "Not ready: {}", # Usernames
|
||||||
|
"all-users-ready" : "Everyone is ready",
|
||||||
|
|
||||||
"identifying-as-controller-notification" : u"Identifying as room controller with password '{}'...",
|
"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.",
|
"failed-to-identify-as-controller-notification" : u"<{}> failed to identify as a room controller.",
|
||||||
@ -42,7 +44,7 @@ en = {
|
|||||||
|
|
||||||
"file-different-notification" : "File you are playing appears to be different from <{}>'s", # User
|
"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): ",
|
"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",
|
"room-files-not-same" : "Not all files the same",
|
||||||
"alone-in-the-room": "You're alone in the room",
|
"alone-in-the-room": "You're alone in the room",
|
||||||
|
|
||||||
"different-filesize-notification" : " (their file size is different from yours!)",
|
"different-filesize-notification" : " (their file size is different from yours!)",
|
||||||
@ -348,13 +350,18 @@ ru = {
|
|||||||
"playing-notification" : u"<{}> включил '{}' ({})", # User, file, duration
|
"playing-notification" : u"<{}> включил '{}' ({})", # User, file, duration
|
||||||
"playing-notification/room-addendum" : u" в комнате: '{}'", # Room
|
"playing-notification/room-addendum" : u" в комнате: '{}'", # Room
|
||||||
|
|
||||||
|
"user-ready-notification" : "<{}> I'm ready", # Username # TODO: Translate into Russian
|
||||||
|
"user-not-ready-notification" : "<{}> I'm not ready", # Username # TODO: Translate into Russian
|
||||||
|
"not-all-ready" : "Not ready: {}", # Usernames # TODO: Translate into Russian
|
||||||
|
"all-users-ready" : "Everyone is ready", # TODO: Translate into Russian
|
||||||
|
|
||||||
"identifying-as-controller-notification" : u"Identifying as room controller with password '{}'...", # TODO: Translate into Russian
|
"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
|
"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
|
"authenticated-as-controller-notification" : u"<{}> authenticated as a room controller", # TODO: Translate into Russian
|
||||||
|
|
||||||
"file-different-notification" : u"Вероятно, файл, который Вы смотрите, отличается от того, который смотрит <{}>.", # User
|
"file-different-notification" : u"Вероятно, файл, который Вы смотрите, отличается от того, который смотрит <{}>.", # User
|
||||||
"file-differences-notification" : u"Ваш файл отличается: ",
|
"file-differences-notification" : u"Ваш файл отличается: ",
|
||||||
"room-files-not-same" : u"Не все пользователи в этой комнате смотрят один и тот же файл.",
|
"room-files-not-same" : u"Не все пользователи в этой комнате смотрят один и тот же файл.", # TODO: Make shorter if possible (to fit better on OSD), e.g. say "Not all files same" or "File mismatch"
|
||||||
"alone-in-the-room" : u"В этой комнате кроме Вас никого нет.",
|
"alone-in-the-room" : u"В этой комнате кроме Вас никого нет.",
|
||||||
|
|
||||||
"different-filesize-notification" : u" (размер Вашего файла не совпадает с размером их файла!)",
|
"different-filesize-notification" : u" (размер Вашего файла не совпадает с размером их файла!)",
|
||||||
@ -657,13 +664,18 @@ de = {
|
|||||||
"playing-notification" : u"<{}> spielt '{}' ({})", # User, file, duration
|
"playing-notification" : u"<{}> spielt '{}' ({})", # User, file, duration
|
||||||
"playing-notification/room-addendum" : u" in Raum: '{}'", # Room
|
"playing-notification/room-addendum" : u" in Raum: '{}'", # Room
|
||||||
|
|
||||||
|
"user-ready-notification" : "<{}> I'm ready", # Username # TODO: Translate into German
|
||||||
|
"user-not-ready-notification" : "<{}> I'm not ready", # Username # TODO: Translate into German
|
||||||
|
"not-all-ready" : "Not ready: {}", # Usernames # TODO: Translate into German
|
||||||
|
"all-users-ready" : "Everyone is ready", # TODO: Translate into German
|
||||||
|
|
||||||
"identifying-as-controller-notification" : u"Identifiziere als Raumleiter mit Passwort '{}'...", # TODO: find a better translation to "room controller"
|
"identifying-as-controller-notification" : u"Identifiziere als Raumleiter mit Passwort '{}'...", # TODO: find a better translation to "room controller"
|
||||||
"failed-to-identify-as-controller-notification" : u"<{}> konnte sich nicht als Raumleiter identifizieren.",
|
"failed-to-identify-as-controller-notification" : u"<{}> konnte sich nicht als Raumleiter identifizieren.",
|
||||||
"authenticated-as-controller-notification" : u"<{}> authentifizierte sich als Raumleiter",
|
"authenticated-as-controller-notification" : u"<{}> authentifizierte sich als Raumleiter",
|
||||||
|
|
||||||
"file-different-notification" : u"Deine Datei scheint sich von <{}>s zu unterscheiden", # User
|
"file-different-notification" : u"Deine Datei scheint sich von <{}>s zu unterscheiden", # User
|
||||||
"file-differences-notification" : u"Deine Datei unterscheidet sich auf folgende Art: ",
|
"file-differences-notification" : u"Deine Datei unterscheidet sich auf folgende Art: ",
|
||||||
"room-files-not-same" : u"Nicht alle Dateien im Raum sind gleich",
|
"room-files-not-same" : u"Nicht alle Dateien im Raum sind gleich", # TODO: Make shorter if possible (to fit better on OSD), e.g. say "Not all files same" or "File mismatch"
|
||||||
"alone-in-the-room": u"Du bist alleine im Raum",
|
"alone-in-the-room": u"Du bist alleine im Raum",
|
||||||
|
|
||||||
"different-filesize-notification" : u" (ihre Dateigröße ist anders als deine!)",
|
"different-filesize-notification" : u" (ihre Dateigröße ist anders als deine!)",
|
||||||
|
|||||||
@ -306,6 +306,7 @@ class MpcHcApi:
|
|||||||
|
|
||||||
class MPCHCAPIPlayer(BasePlayer):
|
class MPCHCAPIPlayer(BasePlayer):
|
||||||
speedSupported = False
|
speedSupported = False
|
||||||
|
secondaryOSDSupported = False
|
||||||
customOpenDialog = False
|
customOpenDialog = False
|
||||||
|
|
||||||
def __init__(self, client):
|
def __init__(self, client):
|
||||||
@ -393,7 +394,7 @@ class MPCHCAPIPlayer(BasePlayer):
|
|||||||
def openFile(self, filePath, resetPosition=False):
|
def openFile(self, filePath, resetPosition=False):
|
||||||
self._mpcApi.openFile(filePath)
|
self._mpcApi.openFile(filePath)
|
||||||
|
|
||||||
def displayMessage(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)
|
self._mpcApi.sendOsd(message, constants.MPC_OSD_POSITION, duration)
|
||||||
|
|
||||||
@retry(MpcHcApi.PlayerNotReadyException, constants.MPC_MAX_RETRIES, constants.MPC_RETRY_WAIT_TIME, 1)
|
@retry(MpcHcApi.PlayerNotReadyException, constants.MPC_MAX_RETRIES, constants.MPC_RETRY_WAIT_TIME, 1)
|
||||||
|
|||||||
@ -10,6 +10,8 @@ import os
|
|||||||
class MplayerPlayer(BasePlayer):
|
class MplayerPlayer(BasePlayer):
|
||||||
speedSupported = True
|
speedSupported = True
|
||||||
customOpenDialog = False
|
customOpenDialog = False
|
||||||
|
secondaryOSDSupported = False
|
||||||
|
|
||||||
RE_ANSWER = re.compile(constants.MPLAYER_ANSWER_REGEX)
|
RE_ANSWER = re.compile(constants.MPLAYER_ANSWER_REGEX)
|
||||||
POSITION_QUERY = 'time_pos'
|
POSITION_QUERY = 'time_pos'
|
||||||
OSD_QUERY = 'osd_show_text'
|
OSD_QUERY = 'osd_show_text'
|
||||||
@ -83,7 +85,7 @@ class MplayerPlayer(BasePlayer):
|
|||||||
def _getProperty(self, property_):
|
def _getProperty(self, property_):
|
||||||
self._listener.sendLine("get_property {}".format(property_))
|
self._listener.sendLine("get_property {}".format(property_))
|
||||||
|
|
||||||
def displayMessage(self, message, duration=(constants.OSD_DURATION * 1000)):
|
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'))
|
self._listener.sendLine(u'{} "{!s}" {} {}'.format(self.OSD_QUERY, message, duration, constants.MPLAYER_OSD_LEVEL).encode('utf-8'))
|
||||||
|
|
||||||
def setSpeed(self, value):
|
def setSpeed(self, value):
|
||||||
|
|||||||
@ -14,6 +14,8 @@ from syncplay.messages import getMessage
|
|||||||
class VlcPlayer(BasePlayer):
|
class VlcPlayer(BasePlayer):
|
||||||
speedSupported = True
|
speedSupported = True
|
||||||
customOpenDialog = False
|
customOpenDialog = False
|
||||||
|
secondaryOSDSupported = True
|
||||||
|
|
||||||
RE_ANSWER = re.compile(constants.VLC_ANSWER_REGEX)
|
RE_ANSWER = re.compile(constants.VLC_ANSWER_REGEX)
|
||||||
SLAVE_ARGS = constants.VLC_SLAVE_ARGS
|
SLAVE_ARGS = constants.VLC_SLAVE_ARGS
|
||||||
if not sys.platform.startswith('darwin'):
|
if not sys.platform.startswith('darwin'):
|
||||||
@ -83,16 +85,19 @@ class VlcPlayer(BasePlayer):
|
|||||||
self._positionAsk.clear()
|
self._positionAsk.clear()
|
||||||
self._pausedAsk.clear()
|
self._pausedAsk.clear()
|
||||||
self._listener.sendLine(".")
|
self._listener.sendLine(".")
|
||||||
if not self._filechanged:
|
if self._filename and not self._filechanged:
|
||||||
self._positionAsk.wait()
|
self._positionAsk.wait()
|
||||||
self._pausedAsk.wait()
|
self._pausedAsk.wait()
|
||||||
self._client.updatePlayerStatus(self._paused, self._position)
|
self._client.updatePlayerStatus(self._paused, self._position)
|
||||||
else:
|
else:
|
||||||
self._client.updatePlayerStatus(self._client.getGlobalPaused(), self._client.getGlobalPosition())
|
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
|
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):
|
def setSpeed(self, value):
|
||||||
self._listener.sendLine("set-rate: {:.2n}".format(value))
|
self._listener.sendLine("set-rate: {:.2n}".format(value))
|
||||||
@ -131,7 +136,10 @@ class VlcPlayer(BasePlayer):
|
|||||||
self._listener.sendLine("get-filename")
|
self._listener.sendLine("get-filename")
|
||||||
|
|
||||||
def lineReceived(self, line):
|
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), "", ""
|
match, name, value = self.RE_ANSWER.match(line), "", ""
|
||||||
if match:
|
if match:
|
||||||
name, value = match.group('command'), match.group('argument')
|
name, value = match.group('command'), match.group('argument')
|
||||||
@ -340,7 +348,7 @@ class VlcPlayer(BasePlayer):
|
|||||||
if self.connected:
|
if self.connected:
|
||||||
try:
|
try:
|
||||||
self.push(line + "\n")
|
self.push(line + "\n")
|
||||||
self._client.ui.showDebugMessage("player >> {}".format(line))
|
self.__playerController._client.ui.showDebugMessage("player >> {}".format(line))
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
if line == "close-vlc":
|
if line == "close-vlc":
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user