Readjust playback using playlists

Instead of fighting against Kodi, work with already set playlist and
adding items to it. Added extra comments to help understand.
This commit is contained in:
angelblue05 2015-10-11 09:25:10 -05:00
parent 5f3f45e404
commit d5f3db078f
3 changed files with 382 additions and 254 deletions

View file

@ -33,7 +33,7 @@ class Kodi_Monitor( xbmc.Monitor ):
#this library monitor is used to detect a watchedstate change by the user through the library
#as well as detect when a library item has been deleted to pass the delete to the Emby server
def onNotification (self,sender,method,data):
def onNotification (self, sender, method, data):
WINDOW = self.WINDOW
downloadUtils = DownloadUtils()
@ -50,6 +50,8 @@ class Kodi_Monitor( xbmc.Monitor ):
if embyid != None:
playurl = xbmc.Player().getPlayingFile()
WINDOW = xbmcgui.Window( 10000 )
username = WINDOW.getProperty('currUser')
userid = WINDOW.getProperty('userId%s' % username)
@ -153,6 +155,12 @@ class Kodi_Monitor( xbmc.Monitor ):
xbmc.log('Deleting via URL: ' + url)
DownloadUtils().downloadUrl(url, type="DELETE")
elif method == "Playlist.OnClear":
self.logMsg("Clear playback properties.", 2)
utils.window('PlaylistIntroSet', clear=True)
utils.window('PlaylistsetDummy', clear=True)
utils.window('PlaylistAdditional', clear=True)
def clearProperty(self, type, id):
# The sleep is necessary since VideoLibrary.OnUpdate
# triggers 4 times in a row.

View file

@ -43,12 +43,11 @@ class PlaybackUtils():
username = utils.window('currUser')
server = utils.window('server%s' % username)
listItem = xbmcgui.ListItem()
id = result['Id']
userdata = result['UserData']
# Get the playurl - direct play, direct stream or transcoding
playurl = PlayUtils().getPlayUrl(server, id, result)
listItem = xbmcgui.ListItem()
if utils.window('playurlFalse') == "true":
# Playurl failed - set in PlayUtils.py
@ -56,6 +55,8 @@ class PlaybackUtils():
self.logMsg("Failed to retrieve the playback path/url or dialog was cancelled.", 1)
return xbmcplugin.setResolvedUrl(int(sys.argv[1]), False, listItem)
############### RESUME POINT ################
# Resume point for widget only
timeInfo = api.getTimeInfo(result)
jumpBackSec = int(utils.settings('resumeJumpBack'))
@ -79,73 +80,164 @@ class PlaybackUtils():
# User selected to start from beginning
seekTime = 0
elif resume_result < 0:
# User cancelled the dialog
else: # User cancelled the dialog
self.logMsg("User cancelled resume dialog.", 1)
return xbmcplugin.setResolvedUrl(int(sys.argv[1]), False, listItem)
############### ORGANIZE CURRENT PLAYLIST ################
# In order, intros, original item requested and any additional parts
playstack = []
# In order, intros, original item requested and any additional part
playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
startPos = max(playlist.getposition(), 0) # Can return -1
sizePlaylist = playlist.size()
currentPosition = startPos
# Check for intros
if utils.settings('disableCinema') == "false" and not seekTime:
self.logMsg("Playlist start position: %s" % startPos, 2)
self.logMsg("Playlist current position: %s" % currentPosition, 2)
self.logMsg("Playlist size: %s" % sizePlaylist, 2)
# Properties to ensure we have have proper playlists with additional items.
introsPlaylist = False
introProperty = utils.window('PlaylistIntroSet') == "true"
dummyProperty = utils.window('PlaylistsetDummy') == "true"
additionalProperty = utils.window('PlaylistAdditional') == "true"
############### -- CHECK FOR INTROS ################
if utils.settings('disableCinema') == "false" and not introProperty and not seekTime:
# if we have any play them when the movie/show is not being resumed
url = "{server}/mediabrowser/Users/{UserId}/Items/%s/Intros?format=json&ImageTypeLimit=1&Fields=Etag" % id
intros = doUtils.downloadUrl(url)
if intros['TotalRecordCount'] != 0:
for intro in intros['Items']:
introPlayurl = PlayUtils().getPlayUrl(server, intro['Id'], intro)
self.setProperties(introPlayurl, intro)
playstack.append(introPlayurl)
# The server randomly returns one custom intro
intro = intros['Items'][0]
introId = intro['Id']
introListItem = xbmcgui.ListItem()
introPlayurl = PlayUtils().getPlayUrl(server, introId, intro)
# Add original item
playstack.append(playurl)
self.setProperties(playurl, result)
self.logMsg("Intro play: %s" % introPlayurl, 1)
self.setProperties(introPlayurl, intro, introListItem)
self.setListItemProps(server, introId, introListItem, intro)
introsPlaylist = True
utils.window('PlaylistIntroSet', value="true")
playlist.add(introPlayurl, introListItem, index=currentPosition)
currentPosition += 1
elif introProperty:
# Play main item, do not play the intro since we already played it. Reset property for next time.
utils.window('PlaylistIntroSet', clear=True)
self.logMsg("Clear intro property.", 2)
############### -- SETUP MAIN ITEM ################
##### Set listitem and properties for main item
self.logMsg("Returned playurl: %s" % playurl, 1)
listItem.setPath(playurl)
self.setProperties(playurl, result, listItem)
mainArt = API().getArtwork(result, "Primary")
listItem.setThumbnailImage(mainArt)
listItem.setIconImage(mainArt)
# Get additional parts/playurl
if result.get('PartCount'):
if introsPlaylist and not sizePlaylist:
# Extend our current playlist with the actual item to play only if there's no playlist first
self.logMsg("No playlist detected at the start. Creating playlist with intro and play item.", 1)
self.logMsg("Playlist current position: %s" % (currentPosition), 1)
playlist.add(playurl, listItem, index=currentPosition)
currentPosition += 1
############### -- CHECK FOR ADDITIONAL PARTS ################
if result.get('PartCount') and not additionalProperty:
# Only add to the playlist after intros have played
url = "{server}/mediabrowser/Videos/%s/AdditionalParts" % id
parts = doUtils.downloadUrl(url)
for part in parts['Items']:
additionalPlayurl = PlayUtils().getPlayUrl(server, part['Id'], part)
self.setProperties(additionalPlayurl, part)
playstack.append(additionalPlayurl)
partId = part['Id']
additionalPlayurl = PlayUtils().getPlayUrl(server, partId, part)
additionalListItem = xbmcgui.ListItem()
# Set listitem and properties for each additional parts
self.logMsg("Adding to playlist: %s position: %s" % (additionalPlayurl, currentPosition), 1)
self.setProperties(additionalPlayurl, part, additionalListItem)
self.setListItemProps(server, partId, additionalListItem, part)
if len(playstack) > 1:
# Convert list in stack:// playurl
playMethod = utils.window('%splaymethod' % playurl)
playurl = "stack://%s" % " , ".join(playstack)
# Set new window properties for combined playurl
utils.window("%splaymethod" % playurl, value=playMethod)
self.setProperties(playurl, result)
# Add item to playlist, after the main item
utils.window('PlaylistAdditional', value="true")
playlist.add(additionalPlayurl, additionalListItem, index=currentPosition+1)
currentPosition += 1
self.logMsg("Returned playurl: %s" % playurl, 1)
listItem.setPath(playurl)
elif additionalProperty:
# Additional parts are already set, reset property for next time
utils.window('PlaylistAdditional', clear=True)
self.logMsg("Clear additional property", 2)
if utils.window("%splaymethod" % playurl) != "Transcode":
# Only for direct play and direct stream
# Append external subtitles to stream
subtitleList = self.externalSubs(id, playurl, server, result['MediaSources'])
listItem.setSubtitles(subtitleList)
############### PLAYBACK ################
# Launch the playback - only set the listitem props if we're not using the setresolvedurl approach
if setup == "service" or xbmc.getCondVisibility('Window.IsActive(home)'):
# Sent via websocketclient.py or default.py but via widgets
self.logMsg("Detecting playback happening via service.py or home menu.", 1)
self.setListItemProps(server, id, listItem, result)
xbmc.Player().play(playurl, listItem)
playlistPlayer = False
if introsPlaylist and not sizePlaylist:
# Extend our current playlist with the actual item to play only if there's no playlist first
playlistPlayer = True
elif sizePlaylist > 0 and not dummyProperty:
# Playlist will fail on the current position. Adding dummy url
playlist.add(playurl, index=startPos)
self.logMsg("Adding dummy path as replacement for position: %s" % startPos, 2)
utils.window('PlaylistsetDummy', value="true")
playlistPlayer = True
elif dummyProperty:
# Already failed, play the item as a single item
utils.window('PlaylistsetDummy', clear=True)
self.logMsg("Clear dummy property.", 2)
if playlistPlayer:
self.logMsg("Processed as a playlist.", 1)
return xbmc.Player().play(playlist)
else:
self.logMsg("Processed as a single item.", 1)
return xbmc.Player().play(playurl, listItem)
elif setup == "default":
# Sent via default.py
xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listItem)
self.logMsg("Detecting playback happening via default.py.", 1)
playlistPlayer = False
def externalSubs(self, id, playurl, server, mediaSources):
if sizePlaylist > 0 and not dummyProperty:
# Playlist will fail on the current position. Adding dummy url
playlist.add(playurl, index=startPos)
self.logMsg("Adding dummy path as replacement for position: %s" % startPos, 2)
utils.window('PlaylistsetDummy', value="true")
playlistPlayer = True
elif dummyProperty:
# Already failed, play the item as a single item
utils.window('PlaylistsetDummy', clear=True)
self.logMsg("Clear dummy property.", 2)
if playlistPlayer:
self.logMsg("Processed as a playlist.", 1)
return xbmc.Player().play(playlist, startpos=startPos)
else: # Sent via default.py
self.logMsg("Processed as a single item.", 1)
return xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listItem)
def externalSubs(self, id, playurl, mediaSources):
username = utils.window('currUser')
server = utils.window('server%s' % username)
externalsubs = []
mapping = {}
@ -176,7 +268,7 @@ class PlaybackUtils():
return externalsubs
def setProperties(self, playurl, result):
def setProperties(self, playurl, result, listItem):
# Set runtimeticks, type, refresh_id and item_id
id = result.get('Id')
type = result.get('Type', "")
@ -190,9 +282,15 @@ class PlaybackUtils():
else:
utils.window("%srefresh_id" % playurl, value=id)
if utils.window("%splaymethod" % playurl) != "Transcode":
# Only for direct play and direct stream
# Append external subtitles to stream
subtitleList = self.externalSubs(id, playurl, result['MediaSources'])
listItem.setSubtitles(subtitleList)
def setArt(self, list, name, path):
if name in ("thumb", "fanart_image", "small_poster", "tiny_poster", "medium_landscape", "medium_poster", "small_fanartimage", "medium_fanartimage", "fanart_noindicators"):
if name in {"thumb", "fanart_image", "small_poster", "tiny_poster", "medium_landscape", "medium_poster", "small_fanartimage", "medium_fanartimage", "fanart_noindicators"}:
list.setProperty(name, path)
else:
list.setArt({name:path})
@ -298,7 +396,7 @@ class PlaybackUtils():
def AddToPlaylist(self, itemIds):
self.logMsg("PlayBackUtils", "== ENTER: PLAYAllItems ==")
self.logMsg("== ENTER: PLAYAllItems ==")
doUtils = self.doUtils
playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)

View file

@ -70,145 +70,179 @@ class Player( xbmc.Player ):
xbmcplayer = self.xbmcplayer
self.stopAll()
# Get current file - if stack://, get currently playing item
currentFile = xbmcplayer.getPlayingFile()
if "stack://" in currentFile:
self.stackFiles = currentFile
currentFile = self.currentStackItem(currentFile)
else:
self.stackFiles = None
self.currentFile = currentFile
self.stackElapsed = 0
# Get current file
try:
currentFile = xbmcplayer.getPlayingFile()
xbmc.sleep(200)
except:
currentFile = ""
count = 0
while not currentFile:
self.logMsg("ONPLAYBACK_STARTED: %s" % currentFile, 0)
xbmc.sleep(100)
try:
currentFile = xbmcplayer.getPlayingFile()
except: pass
# We may need to wait for info to be set in kodi monitor
itemId = utils.window("%sitem_id" % currentFile)
tryCount = 0
while not itemId:
if count == 5: # try 5 times
self.logMsg("Cancelling playback report...", 1)
break
else: count += 1
xbmc.sleep(500)
if currentFile:
# if stack://, get currently playing item
if "stack://" in currentFile:
self.stackFiles = currentFile
currentFile = self.currentStackItem(currentFile)
else:
self.stackFiles = None
self.currentFile = currentFile
self.stackElapsed = 0
self.logMsg("ONPLAYBACK_STARTED: %s" % currentFile, 0)
# We may need to wait for info to be set in kodi monitor
itemId = utils.window("%sitem_id" % currentFile)
if tryCount == 20: # try 20 times or about 10 seconds
break
else: tryCount += 1
tryCount = 0
while not itemId:
else:
# Only proceed if an itemId was found.
runtime = utils.window("%sruntimeticks" % currentFile)
refresh_id = utils.window("%srefresh_id" % currentFile)
playMethod = utils.window("%splaymethod" % currentFile)
itemType = utils.window("%stype" % currentFile)
mapping = utils.window("%sIndexMapping" % currentFile)
seekTime = xbmc.Player().getTime()
self.logMsg("Mapping for subtitles index: %s" % mapping, 2)
# Get playback volume
volume_query = '{"jsonrpc": "2.0", "method": "Application.GetProperties", "params": {"properties": ["volume","muted"]}, "id": 1}'
result = xbmc.executeJSONRPC(volume_query)
result = json.loads(result)
volume = result.get('result').get('volume')
muted = result.get('result').get('muted')
url = "{server}/mediabrowser/Sessions/Playing"
postdata = {
'QueueableMediaTypes': "Video",
'CanSeek': True,
'ItemId': itemId,
'MediaSourceId': itemId,
'PlayMethod': playMethod,
'VolumeLevel': volume,
'PositionTicks': int(seekTime * 10000000) - int(self.stackElapsed * 10000000),
'IsMuted': muted
}
# Get the current audio track and subtitles
if playMethod == "Transcode":
# property set in PlayUtils.py
postdata['AudioStreamIndex'] = utils.window("%sAudioStreamIndex" % currentFile)
postdata['SubtitleStreamIndex'] = utils.window("%sSubtitleStreamIndex" % currentFile)
xbmc.sleep(200)
itemId = utils.window("%sitem_id" % currentFile)
if tryCount == 20: # try 20 times or about 10 seconds
self.logMsg("Could not find itemId, cancelling playback report...", 1)
break
else: tryCount += 1
else:
track_query = '{"jsonrpc": "2.0", "method": "Player.GetProperties", "params": {"playerid": 1,"properties": ["currentsubtitle","currentaudiostream","subtitleenabled"]} , "id": 1}'
result = xbmc.executeJSONRPC(track_query)
# Only proceed if an itemId was found.
runtime = utils.window("%sruntimeticks" % currentFile)
refresh_id = utils.window("%srefresh_id" % currentFile)
playMethod = utils.window("%splaymethod" % currentFile)
itemType = utils.window("%stype" % currentFile)
seekTime = xbmcplayer.getTime()
# Get playback volume
volume_query = '{"jsonrpc": "2.0", "method": "Application.GetProperties", "params": {"properties": ["volume","muted"]}, "id": 1}'
result = xbmc.executeJSONRPC(volume_query)
result = json.loads(result)
result = result.get('result')
# Audio tracks
indexAudio = result.get('result', 0)
if indexAudio:
indexAudio = indexAudio.get('currentaudiostream', {}).get('index', 0)
# Subtitles tracks
indexSubs = result.get('result', 0)
if indexSubs:
indexSubs = indexSubs.get('currentsubtitle', {}).get('index', 0)
# If subtitles are enabled
subsEnabled = result.get('result', "")
if subsEnabled:
subsEnabled = subsEnabled.get('subtitleenabled', "")
volume = result.get('volume')
muted = result.get('muted')
# Postdata for the audio and subs tracks
audioTracks = len(xbmc.Player().getAvailableAudioStreams())
postdata['AudioStreamIndex'] = indexAudio + 1
# Postdata structure to send to Emby server
url = "{server}/mediabrowser/Sessions/Playing"
postdata = {
if subsEnabled and len(xbmc.Player().getAvailableSubtitleStreams()) > 0:
'QueueableMediaTypes': "Video",
'CanSeek': True,
'ItemId': itemId,
'MediaSourceId': itemId,
'PlayMethod': playMethod,
'VolumeLevel': volume,
'PositionTicks': int(seekTime * 10000000) - int(self.stackElapsed * 10000000),
'IsMuted': muted
}
if mapping:
externalIndex = json.loads(mapping)
else: # Direct paths scenario
externalIndex = ""
# Get the current audio track and subtitles
if playMethod == "Transcode":
# property set in PlayUtils.py
postdata['AudioStreamIndex'] = utils.window("%sAudioStreamIndex" % currentFile)
postdata['SubtitleStreamIndex'] = utils.window("%sSubtitleStreamIndex" % currentFile)
if externalIndex:
# If there's external subtitles added via PlaybackUtils
if externalIndex.get(str(indexSubs)):
# If the current subtitle is in the mapping
postdata['SubtitleStreamIndex'] = externalIndex[str(indexSubs)]
else:
# Internal subtitle currently selected
external = len(externalIndex)
postdata['SubtitleStreamIndex'] = indexSubs - external + audioTracks + 1
else:
# Get the current kodi audio and subtitles and convert to Emby equivalent
track_query = '{"jsonrpc": "2.0", "method": "Player.GetProperties", "params": {"playerid": 1,"properties": ["currentsubtitle","currentaudiostream","subtitleenabled"]} , "id": 1}'
result = xbmc.executeJSONRPC(track_query)
result = json.loads(result)
result = result.get('result')
try: # Audio tracks
indexAudio = result['currentaudiostream']['index']
except KeyError:
indexAudio = 0
try: # Subtitles tracks
indexSubs = result['currentsubtitle']['index']
except KeyError:
indexSubs = 0
try: # If subtitles are enabled
subsEnabled = result['subtitleenabled']
except KeyError:
subsEnabled = ""
# Postdata for the audio
postdata['AudioStreamIndex'] = indexAudio + 1
# Postdata for the subtitles
if subsEnabled and len(xbmc.Player().getAvailableSubtitleStreams()) > 0:
# Number of audiotracks to help get Emby Index
audioTracks = len(xbmc.Player().getAvailableAudioStreams())
mapping = utils.window("%sIndexMapping" % currentFile)
if mapping: # Set in PlaybackUtils.py
self.logMsg("Mapping for external subtitles index: %s" % mapping, 2)
externalIndex = json.loads(mapping)
if externalIndex.get(str(indexSubs)):
# If the current subtitle is in the mapping
postdata['SubtitleStreamIndex'] = externalIndex[str(indexSubs)]
else:
# Internal subtitle currently selected
postdata['SubtitleStreamIndex'] = indexSubs - len(externalIndex) + audioTracks + 1
else: # Direct paths enabled scenario or no external subtitles set
postdata['SubtitleStreamIndex'] = indexSubs + audioTracks + 1
else:
# No external subtitles added via PlayUtils
postdata['SubtitleStreamIndex'] = indexSubs + audioTracks + 1
else:
postdata['SubtitleStreamIndex'] = ""
postdata['SubtitleStreamIndex'] = ""
# Post playback to server
self.logMsg("Sending POST play started.", 1)
self.doUtils.downloadUrl(url, postBody=postdata, type="POST")
# save data map for updates and position calls
data = {
# Post playback to server
self.logMsg("Sending POST play started: %s." % postdata, 2)
self.doUtils.downloadUrl(url, postBody=postdata, type="POST")
'runtime': runtime,
'item_id': itemId,
'refresh_id': refresh_id,
'currentfile': currentFile,
'AudioStreamIndex': postdata['AudioStreamIndex'],
'SubtitleStreamIndex': postdata['SubtitleStreamIndex'],
'playmethod': playMethod,
'Type': itemType,
'currentPosition': int(seekTime) - int(self.stackElapsed)
}
# Ensure we do have a runtime
if not runtime:
runtime = xbmcplayer.getTotalTime()
self.logMsg("Runtime is missing, grabbing runtime from Kodi player: %s" % runtime, 1)
self.played_information[currentFile] = data
self.logMsg("ADDING_FILE: %s" % self.played_information, 1)
# Save data map for updates and position calls
data = {
# log some playback stats
'''if(itemType != None):
if(self.playStats.get(itemType) != None):
count = self.playStats.get(itemType) + 1
self.playStats[itemType] = count
else:
self.playStats[itemType] = 1
'runtime': runtime,
'item_id': itemId,
'refresh_id': refresh_id,
'currentfile': currentFile,
'AudioStreamIndex': postdata['AudioStreamIndex'],
'SubtitleStreamIndex': postdata['SubtitleStreamIndex'],
'playmethod': playMethod,
'Type': itemType,
'currentPosition': int(seekTime) - int(self.stackElapsed)
}
if(playMethod != None):
if(self.playStats.get(playMethod) != None):
count = self.playStats.get(playMethod) + 1
self.playStats[playMethod] = count
else:
self.playStats[playMethod] = 1'''
self.played_information[currentFile] = data
self.logMsg("ADDING_FILE: %s" % self.played_information, 1)
# log some playback stats
'''if(itemType != None):
if(self.playStats.get(itemType) != None):
count = self.playStats.get(itemType) + 1
self.playStats[itemType] = count
else:
self.playStats[itemType] = 1
if(playMethod != None):
if(self.playStats.get(playMethod) != None):
count = self.playStats.get(playMethod) + 1
self.playStats[playMethod] = count
else:
self.playStats[playMethod] = 1'''
def reportPlayback(self):
@ -221,25 +255,26 @@ class Player( xbmc.Player ):
# only report playback if emby has initiated the playback (item_id has value)
if data:
# Get playback information
itemId = data.get("item_id")
audioindex = data.get("AudioStreamIndex")
subtitleindex = data.get("SubtitleStreamIndex")
playTime = data.get("currentPosition")
playMethod = data.get("playmethod")
paused = data.get("paused")
itemId = data['item_id']
audioindex = data['AudioStreamIndex']
subtitleindex = data['SubtitleStreamIndex']
playTime = data['currentPosition']
playMethod = data['playmethod']
paused = data.get('paused', False)
if paused is None:
paused = False
# Get playback volume
volume_query = '{"jsonrpc": "2.0", "method": "Application.GetProperties", "params": {"properties": ["volume","muted"]}, "id": 1}'
result = xbmc.executeJSONRPC(volume_query)
result = json.loads(result)
volume = result.get('result').get('volume')
muted = result.get('result').get('muted')
result = result.get('result')
volume = result.get('volume')
muted = result.get('muted')
# Postdata for the websocketclient report
postdata = {
'QueueableMediaTypes': "Video",
@ -247,78 +282,67 @@ class Player( xbmc.Player ):
'ItemId': itemId,
'MediaSourceId': itemId,
'PlayMethod': playMethod,
'PositionTicks': int(playTime * 10000000) - int(self.stackElapsed * 10000000),
'IsPaused': paused,
'VolumeLevel': volume,
'IsMuted': muted
}
if playTime:
postdata['PositionTicks'] = int(playTime * 10000000) - int(self.stackElapsed * 10000000)
if playMethod == "Transcode":
data['AudioStreamIndex'] = audioindex
data['SubtitleStreamIndex'] = subtitleindex
# Track can't be changed, keep reporting the same index
postdata['AudioStreamIndex'] = audioindex
postdata['AudioStreamIndex'] = subtitleindex
else:
# Get current audio and subtitles track
track_query = '{"jsonrpc": "2.0", "method": "Player.GetProperties", "params": {"playerid":1,"properties": ["currentsubtitle","currentaudiostream","subtitleenabled"]} , "id": 1}'
result = xbmc.executeJSONRPC(track_query)
result = json.loads(result)
# Audio tracks
indexAudio = result.get('result', 0)
if indexAudio:
indexAudio = indexAudio.get('currentaudiostream', {}).get('index', 0)
# Subtitles tracks
indexSubs = result.get('result', 0)
if indexSubs:
indexSubs = indexSubs.get('currentsubtitle', {}).get('index', 0)
# If subtitles are enabled
subsEnabled = result.get('result', "")
if subsEnabled:
subsEnabled = subsEnabled.get('subtitleenabled', "")
result = result.get('result')
# Convert back into an Emby index
audioTracks = len(xbmc.Player().getAvailableAudioStreams())
indexAudio = indexAudio + 1
try: # Audio tracks
indexAudio = result['currentaudiostream']['index']
except KeyError:
indexAudio = 0
try: # Subtitles tracks
indexSubs = result['currentsubtitle']['index']
except KeyError:
indexSubs = 0
try: # If subtitles are enabled
subsEnabled = result['subtitleenabled']
except KeyError:
subsEnabled = ""
# Postdata for the audio
data['AudioStreamIndex'], postdata['AudioStreamIndex'] = [indexAudio + 1] * 2
# Postdata for the subtitles
if subsEnabled and len(xbmc.Player().getAvailableSubtitleStreams()) > 0:
WINDOW = xbmcgui.Window(10000)
mapping = WINDOW.getProperty("%sIndexMapping" % currentFile)
if mapping:
# Number of audiotracks to help get Emby Index
audioTracks = len(xbmc.Player().getAvailableAudioStreams())
mapping = utils.window("%sIndexMapping" % currentFile)
if mapping: # Set in PlaybackUtils.py
self.logMsg("Mapping for external subtitles index: %s" % mapping, 2)
externalIndex = json.loads(mapping)
else: # Direct paths scenario
externalIndex = ""
if externalIndex:
# If there's external subtitles added via PlaybackUtils
if externalIndex.get(str(indexSubs)):
# If the current subtitle is in the mapping
indexSubs = externalIndex[str(indexSubs)]
data['SubtitleStreamIndex'], postdata['SubtitleStreamIndex'] = [externalIndex[str(indexSubs)]] * 2
else:
# Internal subtitle currently selected
external = len(externalIndex)
indexSubs = indexSubs - external + audioTracks + 1
else:
# No external subtitles added via PlayUtils
audioTracks = len(xbmc.Player().getAvailableAudioStreams())
indexSubs = indexSubs + audioTracks + 1
else:
indexSubs = ""
data['SubtitleStreamIndex'], postdata['SubtitleStreamIndex'] = [indexSubs - len(externalIndex) + audioTracks + 1] * 2
if audioindex == indexAudio:
postdata['AudioStreamIndex'] = audioindex
else: # Direct paths enabled scenario or no external subtitles set
data['SubtitleStreamIndex'], postdata['SubtitleStreamIndex'] = [indexSubs + audioTracks + 1] * 2
else:
postdata['AudioStreamIndex'] = indexAudio
data['AudioStreamIndex'] = indexAudio
if subtitleindex == indexSubs:
postdata['SubtitleStreamIndex'] = subtitleindex
else:
postdata['SubtitleStreamIndex'] = indexSubs
data['SubtitleStreamIndex'] = indexSubs
data['SubtitleStreamIndex'], postdata['SubtitleStreamIndex'] = [""] * 2
# Report progress via websocketclient
postdata = json.dumps(postdata)
self.logMsg("Report: %s" % postdata, 2)
self.ws.sendProgressUpdate(postdata)
@ -329,9 +353,9 @@ class Player( xbmc.Player ):
self.logMsg("PLAYBACK_PAUSED: %s" % currentFile, 2)
if self.played_information.get(currentFile):
self.played_information[currentFile]['paused'] = "true"
self.played_information[currentFile]['paused'] = True
self.reportPlayback()
self.reportPlayback()
def onPlayBackResumed( self ):
@ -339,22 +363,20 @@ class Player( xbmc.Player ):
self.logMsg("PLAYBACK_RESUMED: %s" % currentFile, 2)
if self.played_information.get(currentFile):
self.played_information[currentFile]['paused'] = "false"
self.played_information[currentFile]['paused'] = False
self.reportPlayback()
self.reportPlayback()
def onPlayBackSeek( self, time, seekOffset ):
self.logMsg("PLAYBACK_SEEK", 2)
xbmcplayer = self.xbmcplayer
# Make position when seeking a bit more accurate
position = xbmcplayer.getTime()
currentFile = self.currentFile
self.logMsg("PLAYBACK_SEEK: %s" % currentFile, 2)
if self.played_information.get(currentFile):
position = self.xbmcplayer.getTime()
self.played_information[currentFile]['currentPosition'] = position
self.reportPlayback()
self.reportPlayback()
def onPlayBackStopped( self ):
# Will be called when user stops xbmc playing a file
@ -371,7 +393,7 @@ class Player( xbmc.Player ):
if not self.played_information:
return
self.logMsg("Played_information: %s" % str(self.played_information), 1)
self.logMsg("Played_information: %s" % self.played_information, 1)
# Process each items
for item in self.played_information:
@ -379,15 +401,15 @@ class Player( xbmc.Player ):
if data:
self.logMsg("Item path: %s" % item, 2)
self.logMsg("Item data: %s" % str(data), 2)
self.logMsg("Item data: %s" % data, 2)
runtime = data.get('runtime')
currentPosition = data.get('currentPosition')
itemId = data.get('item_id')
refresh_id = data.get('refresh_id')
currentFile = data.get('currentfile')
type = data.get('Type')
playMethod = data.get('playmethod')
runtime = data['runtime']
currentPosition = data['currentPosition']
itemId = data['item_id']
refresh_id = data['refresh_id']
currentFile = data['currentfile']
type = data['Type']
playMethod = data['playmethod']
if currentPosition and runtime:
percentComplete = (currentPosition * 10000000) / int(runtime)
@ -409,7 +431,7 @@ class Player( xbmc.Player ):
if percentComplete >= markPlayedAt and offerDelete:
# Item could be stacked, so only offer to delete the main item.
if not self.stackFiles or itemId == utils.window('%sitem_id' % self.stackFiles):
return_value = xbmcgui.Dialog().yesno("Offer Delete", "Delete %s" % data.get('currentfile').split("/")[-1], "on Emby Server?")
return_value = xbmcgui.Dialog().yesno("Offer Delete", "Delete %s" % currentFile.split("/")[-1], "on Emby Server?")
if return_value:
# Delete Kodi entry before Emby
listItem = [itemId]