Fix playback

Intros, additional parts, playlists should now be fully functional... I
hope...
This commit is contained in:
angelblue05 2015-10-12 11:19:44 -05:00
parent dfedf545ba
commit ddd334f285
3 changed files with 131 additions and 137 deletions

View file

@ -157,9 +157,7 @@ class Kodi_Monitor( xbmc.Monitor ):
elif method == "Playlist.OnClear": elif method == "Playlist.OnClear":
self.logMsg("Clear playback properties.", 2) self.logMsg("Clear playback properties.", 2)
utils.window('PlaylistIntroSet', clear=True) utils.window('propertiesPlayback', clear=True)
utils.window('PlaylistsetDummy', clear=True)
utils.window('PlaylistAdditional', clear=True)
def clearProperty(self, type, id): def clearProperty(self, type, id):
# The sleep is necessary since VideoLibrary.OnUpdate # The sleep is necessary since VideoLibrary.OnUpdate

View file

@ -55,6 +55,35 @@ class PlaybackUtils():
self.logMsg("Failed to retrieve the playback path/url or dialog was cancelled.", 1) self.logMsg("Failed to retrieve the playback path/url or dialog was cancelled.", 1)
return xbmcplugin.setResolvedUrl(int(sys.argv[1]), False, listItem) return xbmcplugin.setResolvedUrl(int(sys.argv[1]), False, listItem)
############### -- 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)
############### ORGANIZE CURRENT PLAYLIST ################
homeScreen = xbmc.getCondVisibility('Window.IsActive(home)')
playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
startPos = max(playlist.getposition(), 0) # Can return -1
sizePlaylist = playlist.size()
propertiesPlayback = utils.window('propertiesPlayback') == "true"
introsPlaylist = False
currentPosition = startPos
self.logMsg("Playlist start position: %s" % startPos, 2)
self.logMsg("Playlist plugin position: %s" % currentPosition, 2)
self.logMsg("Playlist size: %s" % sizePlaylist, 2)
############### RESUME POINT ################ ############### RESUME POINT ################
# Resume point for widget only # Resume point for widget only
@ -66,7 +95,7 @@ class PlaybackUtils():
seekTime = seekTime - jumpBackSec seekTime = seekTime - jumpBackSec
# Show the additional resume dialog if launched from a widget # Show the additional resume dialog if launched from a widget
if xbmc.getCondVisibility('Window.IsActive(home)') and seekTime: if homeScreen and seekTime:
# Dialog presentation # Dialog presentation
displayTime = str(datetime.timedelta(seconds=(int(seekTime)))) displayTime = str(datetime.timedelta(seconds=(int(seekTime))))
display_list = ["%s %s" % (self.language(30106), displayTime), self.language(30107)] display_list = ["%s %s" % (self.language(30106), displayTime), self.language(30107)]
@ -84,154 +113,117 @@ class PlaybackUtils():
self.logMsg("User cancelled resume dialog.", 1) self.logMsg("User cancelled resume dialog.", 1)
return xbmcplugin.setResolvedUrl(int(sys.argv[1]), False, listItem) return xbmcplugin.setResolvedUrl(int(sys.argv[1]), False, listItem)
############### ORGANIZE CURRENT PLAYLIST ################ # We need to ensure we add the intro and additional parts only once.
# Otherwise we get a loop.
if not propertiesPlayback:
# In order, intros, original item requested and any additional part utils.window('propertiesPlayback', value="true")
playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO) self.logMsg("Setting up properties in playlist.")
startPos = max(playlist.getposition(), 0) # Can return -1
sizePlaylist = playlist.size()
currentPosition = startPos
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) ############### -- CHECK FOR INTROS ################
if intros['TotalRecordCount'] != 0:
# The server randomly returns one custom intro
intro = intros['Items'][0]
introId = intro['Id']
introListItem = xbmcgui.ListItem()
introPlayurl = PlayUtils().getPlayUrl(server, introId, intro)
self.logMsg("Intro play: %s" % introPlayurl, 1) if utils.settings('disableCinema') == "false" 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)
self.setProperties(introPlayurl, intro, introListItem) if intros['TotalRecordCount'] != 0:
self.setListItemProps(server, introId, introListItem, intro) for intro in intros['Items']:
# The server randomly returns intros, process them.
introsPlaylist = True introId = intro['Id']
utils.window('PlaylistIntroSet', value="true")
playlist.add(introPlayurl, introListItem, index=currentPosition) introPlayurl = PlayUtils().getPlayUrl(server, introId, intro)
currentPosition += 1 introListItem = xbmcgui.ListItem()
self.logMsg("Adding Intro: %s" % introPlayurl, 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 intros
self.setProperties(introPlayurl, intro, introListItem)
##### Set listitem and properties for main item self.setListItemProps(server, introId, introListItem, intro)
self.logMsg("Returned playurl: %s" % playurl, 1)
listItem.setPath(playurl) playlist.add(introPlayurl, introListItem, index=currentPosition)
self.setProperties(playurl, result, listItem) introsPlaylist = True
currentPosition += 1
mainArt = API().getArtwork(result, "Primary")
listItem.setThumbnailImage(mainArt)
listItem.setIconImage(mainArt)
if introsPlaylist and not sizePlaylist: ############### -- ADD MAIN ITEM ONLY FOR HOMESCREEN ###############
# 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) if homeScreen and not sizePlaylist:
self.logMsg("Playlist current position: %s" % (currentPosition), 1) # Extend our current playlist with the actual item to play only if there's no playlist first
playlist.add(playurl, listItem, index=currentPosition) self.logMsg("Adding main item to playlist.", 1)
self.setListItemProps(server, id, listItem, result)
playlist.add(playurl, listItem, index=currentPosition)
# Ensure that additional parts are played after the main item
currentPosition += 1 currentPosition += 1
############### -- CHECK FOR ADDITIONAL PARTS ################
if result.get('PartCount') and not additionalProperty: ############### -- CHECK FOR ADDITIONAL PARTS ################
# Only add to the playlist after intros have played
url = "{server}/mediabrowser/Videos/%s/AdditionalParts" % id
parts = doUtils.downloadUrl(url) if result.get('PartCount'):
for part in parts['Items']: # Only add to the playlist after intros have played
partId = part['Id'] partcount = result['PartCount']
additionalPlayurl = PlayUtils().getPlayUrl(server, partId, part) url = "{server}/mediabrowser/Videos/%s/AdditionalParts" % id
additionalListItem = xbmcgui.ListItem() parts = doUtils.downloadUrl(url)
# Set listitem and properties for each additional parts for part in parts['Items']:
self.logMsg("Adding to playlist: %s position: %s" % (additionalPlayurl, currentPosition), 1)
self.setProperties(additionalPlayurl, part, additionalListItem)
self.setListItemProps(server, partId, additionalListItem, part)
# Add item to playlist, after the main item partId = part['Id']
utils.window('PlaylistAdditional', value="true") additionalPlayurl = PlayUtils().getPlayUrl(server, partId, part)
playlist.add(additionalPlayurl, additionalListItem, index=currentPosition+1) additionalListItem = xbmcgui.ListItem()
self.logMsg("Adding additional part: %s" % partcount, 1)
# Set listitem and properties for each additional parts
self.setProperties(additionalPlayurl, part, additionalListItem)
self.setListItemProps(server, partId, additionalListItem, part)
playlist.add(additionalPlayurl, additionalListItem, index=currentPosition)
currentPosition += 1
############### ADD DUMMY TO PLAYLIST #################
if (not homeScreen and introsPlaylist) or (homeScreen and sizePlaylist > 0):
# Playlist will fail on the current position. Adding dummy url
self.logMsg("Adding dummy url to counter the setResolvedUrl error.", 2)
playlist.add(playurl, index=startPos)
currentPosition += 1 currentPosition += 1
elif additionalProperty:
# Additional parts are already set, reset property for next time # We just skipped adding properties. Reset flag for next time.
utils.window('PlaylistAdditional', clear=True) elif propertiesPlayback:
self.logMsg("Clear additional property", 2) self.logMsg("Resetting properties playback flag.", 2)
utils.window('propertiesPlayback', clear=True)
self.verifyPlaylist()
############### PLAYBACK ################ ############### PLAYBACK ################
if setup == "service" or xbmc.getCondVisibility('Window.IsActive(home)'): if not homeScreen and not introsPlaylist:
# 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)
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":
self.logMsg("Detecting playback happening via default.py.", 1)
playlistPlayer = False
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 single item.", 1)
self.logMsg("Processed as a playlist.", 1) xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listItem)
return xbmc.Player().play(playlist, startpos=startPos)
else: # Sent via default.py elif not homeScreen:
self.logMsg("Processed as a single item.", 1)
return xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listItem) self.logMsg("Processed as a playlist. First item is skipped.", 1)
xbmcplugin.setResolvedUrl(int(sys.argv[1]), False, listItem)
else:
self.logMsg("Play as a regular item.", 1)
xbmc.Player().play(playlist, startpos=startPos)
def verifyPlaylist(self):
playlistitems = '{"jsonrpc": "2.0", "method": "Playlist.GetItems", "params": { "playlistid": 1 }, "id": 1}'
items = xbmc.executeJSONRPC(playlistitems)
self.logMsg(items, 2)
def removeFromPlaylist(self, pos):
playlistremove = '{"jsonrpc": "2.0", "method": "Playlist.Remove", "params": { "playlistid": 1, "position": %d }, "id": 1}' % pos
result = xbmc.executeJSONRPC(playlistremove)
self.logMsg(result, 1)
def externalSubs(self, id, playurl, mediaSources): def externalSubs(self, id, playurl, mediaSources):
@ -268,6 +260,7 @@ class PlaybackUtils():
return externalsubs return externalsubs
def setProperties(self, playurl, result, listItem): def setProperties(self, playurl, result, listItem):
# Set runtimeticks, type, refresh_id and item_id # Set runtimeticks, type, refresh_id and item_id
id = result.get('Id') id = result.get('Id')
@ -290,7 +283,7 @@ class PlaybackUtils():
def setArt(self, list, name, path): 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) list.setProperty(name, path)
else: else:
list.setArt({name:path}) list.setArt({name:path})
@ -333,6 +326,7 @@ class PlaybackUtils():
listItem.setProperty('IsPlayable', 'true') listItem.setProperty('IsPlayable', 'true')
listItem.setProperty('IsFolder', 'false') listItem.setProperty('IsFolder', 'false')
listItem.setLabel(metadata['title'])
listItem.setInfo('video', infoLabels=metadata) listItem.setInfo('video', infoLabels=metadata)
# Set artwork for listitem # Set artwork for listitem

View file

@ -208,7 +208,9 @@ class Player( xbmc.Player ):
self.doUtils.downloadUrl(url, postBody=postdata, type="POST") self.doUtils.downloadUrl(url, postBody=postdata, type="POST")
# Ensure we do have a runtime # Ensure we do have a runtime
if not runtime: try:
runtime = int(runtime)
except ValueError:
runtime = xbmcplayer.getTotalTime() runtime = xbmcplayer.getTotalTime()
self.logMsg("Runtime is missing, grabbing runtime from Kodi player: %s" % runtime, 1) self.logMsg("Runtime is missing, grabbing runtime from Kodi player: %s" % runtime, 1)