mirror of
https://github.com/jellyfin/jellyfin-kodi.git
synced 2024-12-24 17:56:11 +00:00
Fix playback
Intros, additional parts, playlists should now be fully functional... I hope...
This commit is contained in:
parent
dfedf545ba
commit
ddd334f285
3 changed files with 131 additions and 137 deletions
|
@ -157,9 +157,7 @@ class Kodi_Monitor( xbmc.Monitor ):
|
|||
|
||||
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)
|
||||
utils.window('propertiesPlayback', clear=True)
|
||||
|
||||
def clearProperty(self, type, id):
|
||||
# The sleep is necessary since VideoLibrary.OnUpdate
|
||||
|
|
|
@ -55,6 +55,35 @@ 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)
|
||||
|
||||
|
||||
############### -- 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 for widget only
|
||||
|
@ -66,7 +95,7 @@ class PlaybackUtils():
|
|||
seekTime = seekTime - jumpBackSec
|
||||
|
||||
# Show the additional resume dialog if launched from a widget
|
||||
if xbmc.getCondVisibility('Window.IsActive(home)') and seekTime:
|
||||
if homeScreen and seekTime:
|
||||
# Dialog presentation
|
||||
displayTime = str(datetime.timedelta(seconds=(int(seekTime))))
|
||||
display_list = ["%s %s" % (self.language(30106), displayTime), self.language(30107)]
|
||||
|
@ -84,154 +113,117 @@ class PlaybackUtils():
|
|||
self.logMsg("User cancelled resume dialog.", 1)
|
||||
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
|
||||
playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
|
||||
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"
|
||||
utils.window('propertiesPlayback', value="true")
|
||||
self.logMsg("Setting up properties in playlist.")
|
||||
|
||||
############### -- CHECK FOR INTROS ################
|
||||
|
||||
if utils.settings('disableCinema') == "false" and not introProperty and not seekTime:
|
||||
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)
|
||||
|
||||
if intros['TotalRecordCount'] != 0:
|
||||
# The server randomly returns one custom intro
|
||||
intro = intros['Items'][0]
|
||||
for intro in intros['Items']:
|
||||
# The server randomly returns intros, process them.
|
||||
introId = intro['Id']
|
||||
introListItem = xbmcgui.ListItem()
|
||||
|
||||
introPlayurl = PlayUtils().getPlayUrl(server, introId, intro)
|
||||
introListItem = xbmcgui.ListItem()
|
||||
self.logMsg("Adding Intro: %s" % introPlayurl, 1)
|
||||
|
||||
self.logMsg("Intro play: %s" % introPlayurl, 1)
|
||||
|
||||
# Set listitem and properties for intros
|
||||
self.setProperties(introPlayurl, intro, introListItem)
|
||||
self.setListItemProps(server, introId, introListItem, intro)
|
||||
|
||||
introsPlaylist = True
|
||||
utils.window('PlaylistIntroSet', value="true")
|
||||
playlist.add(introPlayurl, introListItem, index=currentPosition)
|
||||
introsPlaylist = True
|
||||
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 ################
|
||||
############### -- ADD MAIN ITEM ONLY FOR HOMESCREEN ###############
|
||||
|
||||
##### 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)
|
||||
|
||||
if introsPlaylist and not sizePlaylist:
|
||||
if homeScreen 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)
|
||||
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
|
||||
|
||||
|
||||
############### -- CHECK FOR ADDITIONAL PARTS ################
|
||||
|
||||
if result.get('PartCount') and not additionalProperty:
|
||||
if result.get('PartCount'):
|
||||
# Only add to the playlist after intros have played
|
||||
partcount = result['PartCount']
|
||||
url = "{server}/mediabrowser/Videos/%s/AdditionalParts" % id
|
||||
|
||||
parts = doUtils.downloadUrl(url)
|
||||
|
||||
for part in parts['Items']:
|
||||
|
||||
partId = part['Id']
|
||||
additionalPlayurl = PlayUtils().getPlayUrl(server, partId, part)
|
||||
additionalListItem = xbmcgui.ListItem()
|
||||
self.logMsg("Adding additional part: %s" % partcount, 1)
|
||||
|
||||
# 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)
|
||||
|
||||
# Add item to playlist, after the main item
|
||||
utils.window('PlaylistAdditional', value="true")
|
||||
playlist.add(additionalPlayurl, additionalListItem, index=currentPosition+1)
|
||||
playlist.add(additionalPlayurl, additionalListItem, index=currentPosition)
|
||||
currentPosition += 1
|
||||
|
||||
elif additionalProperty:
|
||||
# Additional parts are already set, reset property for next time
|
||||
utils.window('PlaylistAdditional', clear=True)
|
||||
self.logMsg("Clear additional property", 2)
|
||||
|
||||
############### 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
|
||||
|
||||
|
||||
# We just skipped adding properties. Reset flag for next time.
|
||||
elif propertiesPlayback:
|
||||
self.logMsg("Resetting properties playback flag.", 2)
|
||||
utils.window('propertiesPlayback', clear=True)
|
||||
|
||||
self.verifyPlaylist()
|
||||
|
||||
############### PLAYBACK ################
|
||||
|
||||
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)
|
||||
if not homeScreen and not introsPlaylist:
|
||||
|
||||
playlistPlayer = False
|
||||
self.logMsg("Processed as a single item.", 1)
|
||||
xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listItem)
|
||||
|
||||
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 not homeScreen:
|
||||
|
||||
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
|
||||
self.logMsg("Processed as a playlist. First item is skipped.", 1)
|
||||
xbmcplugin.setResolvedUrl(int(sys.argv[1]), False, listItem)
|
||||
|
||||
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)
|
||||
self.logMsg("Play as a regular item.", 1)
|
||||
xbmc.Player().play(playlist, startpos=startPos)
|
||||
|
||||
|
||||
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 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):
|
||||
|
@ -268,6 +260,7 @@ class PlaybackUtils():
|
|||
|
||||
return externalsubs
|
||||
|
||||
|
||||
def setProperties(self, playurl, result, listItem):
|
||||
# Set runtimeticks, type, refresh_id and item_id
|
||||
id = result.get('Id')
|
||||
|
@ -290,7 +283,7 @@ class PlaybackUtils():
|
|||
|
||||
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})
|
||||
|
@ -333,6 +326,7 @@ class PlaybackUtils():
|
|||
|
||||
listItem.setProperty('IsPlayable', 'true')
|
||||
listItem.setProperty('IsFolder', 'false')
|
||||
listItem.setLabel(metadata['title'])
|
||||
listItem.setInfo('video', infoLabels=metadata)
|
||||
|
||||
# Set artwork for listitem
|
||||
|
|
|
@ -208,7 +208,9 @@ class Player( xbmc.Player ):
|
|||
self.doUtils.downloadUrl(url, postBody=postdata, type="POST")
|
||||
|
||||
# Ensure we do have a runtime
|
||||
if not runtime:
|
||||
try:
|
||||
runtime = int(runtime)
|
||||
except ValueError:
|
||||
runtime = xbmcplayer.getTotalTime()
|
||||
self.logMsg("Runtime is missing, grabbing runtime from Kodi player: %s" % runtime, 1)
|
||||
|
||||
|
|
Loading…
Reference in a new issue