This commit is contained in:
SpootDev 2016-03-31 10:58:49 -05:00
parent 065bff5215
commit 243a12c263

View file

@ -1,358 +1,357 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
################################################################################################# #################################################################################################
import json import json
import sys import sys
import xbmc import xbmc
import xbmcgui import xbmcgui
import xbmcplugin import xbmcplugin
import api import api
import artwork import artwork
import clientinfo import clientinfo
import downloadutils import downloadutils
import playutils as putils import playutils as putils
import playlist import playlist
import read_embyserver as embyserver import read_embyserver as embyserver
import utils import utils
################################################################################################# #################################################################################################
class PlaybackUtils(): class PlaybackUtils():
def __init__(self, item): def __init__(self, item):
self.item = item self.item = item
self.API = api.API(self.item) self.API = api.API(self.item)
self.clientInfo = clientinfo.ClientInfo() self.clientInfo = clientinfo.ClientInfo()
self.addonName = self.clientInfo.getAddonName() self.addonName = self.clientInfo.getAddonName()
self.doUtils = downloadutils.DownloadUtils().downloadUrl self.doUtils = downloadutils.DownloadUtils().downloadUrl
self.userid = utils.window('emby_currUser') self.userid = utils.window('emby_currUser')
self.server = utils.window('emby_server%s' % self.userid) self.server = utils.window('emby_server%s' % self.userid)
self.artwork = artwork.Artwork() self.artwork = artwork.Artwork()
self.emby = embyserver.Read_EmbyServer() self.emby = embyserver.Read_EmbyServer()
self.pl = playlist.Playlist() self.pl = playlist.Playlist()
def logMsg(self, msg, lvl=1): def logMsg(self, msg, lvl=1):
self.className = self.__class__.__name__ self.className = self.__class__.__name__
utils.logMsg("%s %s" % (self.addonName, self.className), msg, lvl) utils.logMsg("%s %s" % (self.addonName, self.className), msg, lvl)
def play(self, itemid, dbid=None): def play(self, itemid, dbid=None):
log = self.logMsg window = utils.window
window = utils.window settings = utils.settings
settings = utils.settings
doUtils = self.doUtils
doUtils = self.doUtils item = self.item
item = self.item API = self.API
API = self.API listitem = xbmcgui.ListItem()
listitem = xbmcgui.ListItem() playutils = putils.PlayUtils(item)
playutils = putils.PlayUtils(item)
self.logMsg("Play called.", 1)
log("Play called.", 1) playurl = playutils.getPlayUrl()
playurl = playutils.getPlayUrl() if not playurl:
if not playurl: return xbmcplugin.setResolvedUrl(int(sys.argv[1]), False, listitem)
return xbmcplugin.setResolvedUrl(int(sys.argv[1]), False, listitem)
if dbid is None:
if dbid is None: # Item is not in Kodi database
# Item is not in Kodi database listitem.setPath(playurl)
listitem.setPath(playurl) self.setProperties(playurl, listitem)
self.setProperties(playurl, listitem) return xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listitem)
return xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listitem)
############### ORGANIZE CURRENT PLAYLIST ################
############### ORGANIZE CURRENT PLAYLIST ################
homeScreen = xbmc.getCondVisibility('Window.IsActive(home)')
homeScreen = xbmc.getCondVisibility('Window.IsActive(home)') playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO) startPos = max(playlist.getposition(), 0) # Can return -1
startPos = max(playlist.getposition(), 0) # Can return -1 sizePlaylist = playlist.size()
sizePlaylist = playlist.size() currentPosition = startPos
currentPosition = startPos
propertiesPlayback = window('emby_playbackProps') == "true"
propertiesPlayback = window('emby_playbackProps') == "true" introsPlaylist = False
introsPlaylist = False dummyPlaylist = False
dummyPlaylist = False
self.logMsg("Playlist start position: %s" % startPos, 2)
log("Playlist start position: %s" % startPos, 2) self.logMsg("Playlist plugin position: %s" % currentPosition, 2)
log("Playlist plugin position: %s" % currentPosition, 2) self.logMsg("Playlist size: %s" % sizePlaylist, 2)
log("Playlist size: %s" % sizePlaylist, 2)
############### RESUME POINT ################
############### RESUME POINT ################
userdata = API.getUserData()
userdata = API.getUserData() seektime = API.adjustResume(userdata['Resume'])
seektime = API.adjustResume(userdata['Resume'])
# We need to ensure we add the intro and additional parts only once.
# We need to ensure we add the intro and additional parts only once. # Otherwise we get a loop.
# Otherwise we get a loop. if not propertiesPlayback:
if not propertiesPlayback:
window('emby_playbackProps', value="true")
window('emby_playbackProps', value="true") self.logMsg("Setting up properties in playlist.", 1)
log("Setting up properties in playlist.", 1)
if (not homeScreen and not seektime and
if (not homeScreen and not seektime and window('emby_customPlaylist') != "true"):
window('emby_customPlaylist') != "true"):
self.logMsg("Adding dummy file to playlist.", 2)
log("Adding dummy file to playlist.", 2) dummyPlaylist = True
dummyPlaylist = True playlist.add(playurl, listitem, index=startPos)
playlist.add(playurl, listitem, index=startPos) # Remove the original item from playlist
# Remove the original item from playlist self.pl.removefromPlaylist(startPos+1)
self.pl.removefromPlaylist(startPos+1) # Readd the original item to playlist - via jsonrpc so we have full metadata
# Readd the original item to playlist - via jsonrpc so we have full metadata self.pl.insertintoPlaylist(currentPosition+1, dbid, item['Type'].lower())
self.pl.insertintoPlaylist(currentPosition+1, dbid, item['Type'].lower()) currentPosition += 1
currentPosition += 1
############### -- CHECK FOR INTROS ################
############### -- CHECK FOR INTROS ################
if settings('enableCinema') == "true" and not seektime:
if settings('enableCinema') == "true" and not seektime: # if we have any play them when the movie/show is not being resumed
# if we have any play them when the movie/show is not being resumed url = "{server}/emby/Users/{UserId}/Items/%s/Intros?format=json" % itemid
url = "{server}/emby/Users/{UserId}/Items/%s/Intros?format=json" % itemid intros = doUtils(url)
intros = doUtils(url)
if intros['TotalRecordCount'] != 0:
if intros['TotalRecordCount'] != 0: getTrailers = True
getTrailers = True
if settings('askCinema') == "true":
if settings('askCinema') == "true": resp = xbmcgui.Dialog().yesno("Emby for Kodi", utils.language(33016))
resp = xbmcgui.Dialog().yesno("Emby for Kodi", utils.language(33016)) if not resp:
if not resp: # User selected to not play trailers
# User selected to not play trailers getTrailers = False
getTrailers = False self.logMsg("Skip trailers.", 1)
log("Skip trailers.", 1)
if getTrailers:
if getTrailers: for intro in intros['Items']:
for intro in intros['Items']: # The server randomly returns intros, process them.
# The server randomly returns intros, process them. introListItem = xbmcgui.ListItem()
introListItem = xbmcgui.ListItem() introPlayurl = putils.PlayUtils(intro).getPlayUrl()
introPlayurl = putils.PlayUtils(intro).getPlayUrl() self.logMsg("Adding Intro: %s" % introPlayurl, 1)
log("Adding Intro: %s" % introPlayurl, 1)
# Set listitem and properties for intros
# Set listitem and properties for intros pbutils = PlaybackUtils(intro)
pbutils = PlaybackUtils(intro) pbutils.setProperties(introPlayurl, introListItem)
pbutils.setProperties(introPlayurl, introListItem)
self.pl.insertintoPlaylist(currentPosition, url=introPlayurl)
self.pl.insertintoPlaylist(currentPosition, url=introPlayurl) introsPlaylist = True
introsPlaylist = True currentPosition += 1
currentPosition += 1
############### -- ADD MAIN ITEM ONLY FOR HOMESCREEN ###############
############### -- ADD MAIN ITEM ONLY FOR HOMESCREEN ###############
if homeScreen and not seektime and not sizePlaylist:
if homeScreen and not seektime and not sizePlaylist: # Extend our current playlist with the actual item to play
# Extend our current playlist with the actual item to play # only if there's no playlist first
# only if there's no playlist first self.logMsg("Adding main item to playlist.", 1)
log("Adding main item to playlist.", 1) self.pl.addtoPlaylist(dbid, item['Type'].lower())
self.pl.addtoPlaylist(dbid, item['Type'].lower())
# Ensure that additional parts are played after the main item
# Ensure that additional parts are played after the main item currentPosition += 1
currentPosition += 1
############### -- CHECK FOR ADDITIONAL PARTS ################
############### -- CHECK FOR ADDITIONAL PARTS ################
if item.get('PartCount'):
if item.get('PartCount'): # Only add to the playlist after intros have played
# Only add to the playlist after intros have played partcount = item['PartCount']
partcount = item['PartCount'] url = "{server}/emby/Videos/%s/AdditionalParts?format=json" % itemid
url = "{server}/emby/Videos/%s/AdditionalParts?format=json" % itemid parts = doUtils(url)
parts = doUtils(url) for part in parts['Items']:
for part in parts['Items']:
additionalListItem = xbmcgui.ListItem()
additionalListItem = xbmcgui.ListItem() additionalPlayurl = putils.PlayUtils(part).getPlayUrl()
additionalPlayurl = putils.PlayUtils(part).getPlayUrl() self.logMsg("Adding additional part: %s" % partcount, 1)
log("Adding additional part: %s" % partcount, 1)
# Set listitem and properties for each additional parts
# Set listitem and properties for each additional parts pbutils = PlaybackUtils(part)
pbutils = PlaybackUtils(part) pbutils.setProperties(additionalPlayurl, additionalListItem)
pbutils.setProperties(additionalPlayurl, additionalListItem) pbutils.setArtwork(additionalListItem)
pbutils.setArtwork(additionalListItem)
playlist.add(additionalPlayurl, additionalListItem, index=currentPosition)
playlist.add(additionalPlayurl, additionalListItem, index=currentPosition) self.pl.verifyPlaylist()
self.pl.verifyPlaylist() currentPosition += 1
currentPosition += 1
if dummyPlaylist:
if dummyPlaylist: # Added a dummy file to the playlist,
# Added a dummy file to the playlist, # because the first item is going to fail automatically.
# because the first item is going to fail automatically. self.logMsg("Processed as a playlist. First item is skipped.", 1)
log("Processed as a playlist. First item is skipped.", 1) return xbmcplugin.setResolvedUrl(int(sys.argv[1]), False, listitem)
return xbmcplugin.setResolvedUrl(int(sys.argv[1]), False, listitem)
# We just skipped adding properties. Reset flag for next time.
# We just skipped adding properties. Reset flag for next time. elif propertiesPlayback:
elif propertiesPlayback: self.logMsg("Resetting properties playback flag.", 2)
log("Resetting properties playback flag.", 2) window('emby_playbackProps', clear=True)
window('emby_playbackProps', clear=True)
#self.pl.verifyPlaylist()
#self.pl.verifyPlaylist() ########## SETUP MAIN ITEM ##########
########## SETUP MAIN ITEM ##########
# For transcoding only, ask for audio/subs pref
# For transcoding only, ask for audio/subs pref if window('emby_%s.playmethod' % playurl) == "Transcode":
if window('emby_%s.playmethod' % playurl) == "Transcode": playurl = playutils.audioSubsPref(playurl, listitem)
playurl = playutils.audioSubsPref(playurl, listitem) window('emby_%s.playmethod' % playurl, value="Transcode")
window('emby_%s.playmethod' % playurl, value="Transcode")
listitem.setPath(playurl)
listitem.setPath(playurl) self.setProperties(playurl, listitem)
self.setProperties(playurl, listitem)
############### PLAYBACK ################
############### PLAYBACK ################
if homeScreen and seektime and window('emby_customPlaylist') != "true":
if homeScreen and seektime and window('emby_customPlaylist') != "true": self.logMsg("Play as a widget item.", 1)
log("Play as a widget item.", 1) self.setListItem(listitem)
self.setListItem(listitem) xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listitem)
xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listitem)
elif ((introsPlaylist and window('emby_customPlaylist') == "true") or
elif ((introsPlaylist and window('emby_customPlaylist') == "true") or (homeScreen and not sizePlaylist)):
(homeScreen and not sizePlaylist)): # Playlist was created just now, play it.
# Playlist was created just now, play it. self.logMsg("Play playlist.", 1)
log("Play playlist.", 1) xbmc.Player().play(playlist, startpos=startPos)
xbmc.Player().play(playlist, startpos=startPos)
else:
else: self.logMsg("Play as a regular item.", 1)
log("Play as a regular item.", 1) xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listitem)
xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listitem)
def setProperties(self, playurl, listitem):
def setProperties(self, playurl, listitem):
window = utils.window
window = utils.window # Set all properties necessary for plugin path playback
# Set all properties necessary for plugin path playback item = self.item
item = self.item itemid = item['Id']
itemid = item['Id'] itemtype = item['Type']
itemtype = item['Type']
embyitem = "emby_%s" % playurl
embyitem = "emby_%s" % playurl window('%s.runtime' % embyitem, value=str(item.get('RunTimeTicks')))
window('%s.runtime' % embyitem, value=str(item.get('RunTimeTicks'))) window('%s.type' % embyitem, value=itemtype)
window('%s.type' % embyitem, value=itemtype) window('%s.itemid' % embyitem, value=itemid)
window('%s.itemid' % embyitem, value=itemid)
if itemtype == "Episode":
if itemtype == "Episode": window('%s.refreshid' % embyitem, value=item.get('SeriesId'))
window('%s.refreshid' % embyitem, value=item.get('SeriesId')) else:
else: window('%s.refreshid' % embyitem, value=itemid)
window('%s.refreshid' % embyitem, value=itemid)
# Append external subtitles to stream
# Append external subtitles to stream playmethod = utils.window('%s.playmethod' % embyitem)
playmethod = utils.window('%s.playmethod' % embyitem) # Only for direct stream
# Only for direct stream if playmethod in ("DirectStream"):
if playmethod in ("DirectStream"): # Direct play automatically appends external
# Direct play automatically appends external subtitles = self.externalSubs(playurl)
subtitles = self.externalSubs(playurl) listitem.setSubtitles(subtitles)
listitem.setSubtitles(subtitles)
self.setArtwork(listitem)
self.setArtwork(listitem)
def externalSubs(self, playurl):
def externalSubs(self, playurl):
externalsubs = []
externalsubs = [] mapping = {}
mapping = {}
item = self.item
item = self.item itemid = item['Id']
itemid = item['Id'] try:
try: mediastreams = item['MediaSources'][0]['MediaStreams']
mediastreams = item['MediaSources'][0]['MediaStreams'] except (TypeError, KeyError, IndexError):
except (TypeError, KeyError, IndexError): return
return
kodiindex = 0
kodiindex = 0 for stream in mediastreams:
for stream in mediastreams:
index = stream['Index']
index = stream['Index'] # Since Emby returns all possible tracks together, have to pull only external subtitles.
# Since Emby returns all possible tracks together, have to pull only external subtitles. # IsTextSubtitleStream if true, is available to download from emby.
# IsTextSubtitleStream if true, is available to download from emby. if (stream['Type'] == "Subtitle" and
if (stream['Type'] == "Subtitle" and stream['IsExternal'] and stream['IsTextSubtitleStream']):
stream['IsExternal'] and stream['IsTextSubtitleStream']):
# Direct stream
# Direct stream url = ("%s/Videos/%s/%s/Subtitles/%s/Stream.srt"
url = ("%s/Videos/%s/%s/Subtitles/%s/Stream.srt" % (self.server, itemid, itemid, index))
% (self.server, itemid, itemid, index))
# map external subtitles for mapping
# map external subtitles for mapping mapping[kodiindex] = index
mapping[kodiindex] = index externalsubs.append(url)
externalsubs.append(url) kodiindex += 1
kodiindex += 1
mapping = json.dumps(mapping)
mapping = json.dumps(mapping) utils.window('emby_%s.indexMapping' % playurl, value=mapping)
utils.window('emby_%s.indexMapping' % playurl, value=mapping)
return externalsubs
return externalsubs
def setArtwork(self, listItem):
def setArtwork(self, listItem): # Set up item and item info
# Set up item and item info item = self.item
item = self.item artwork = self.artwork
artwork = self.artwork
allartwork = artwork.getAllArtwork(item, parentInfo=True)
allartwork = artwork.getAllArtwork(item, parentInfo=True) # Set artwork for listitem
# Set artwork for listitem arttypes = {
arttypes = {
'poster': "Primary",
'poster': "Primary", 'tvshow.poster': "Primary",
'tvshow.poster': "Primary", 'clearart': "Art",
'clearart': "Art", 'tvshow.clearart': "Art",
'tvshow.clearart': "Art", 'clearlogo': "Logo",
'clearlogo': "Logo", 'tvshow.clearlogo': "Logo",
'tvshow.clearlogo': "Logo", 'discart': "Disc",
'discart': "Disc", 'fanart_image': "Backdrop",
'fanart_image': "Backdrop", 'landscape': "Thumb"
'landscape': "Thumb" }
} for arttype in arttypes:
for arttype in arttypes:
art = arttypes[arttype]
art = arttypes[arttype] if art == "Backdrop":
if art == "Backdrop": try: # Backdrop is a list, grab the first backdrop
try: # Backdrop is a list, grab the first backdrop self.setArtProp(listItem, arttype, allartwork[art][0])
self.setArtProp(listItem, arttype, allartwork[art][0]) except: pass
except: pass else:
else: self.setArtProp(listItem, arttype, allartwork[art])
self.setArtProp(listItem, arttype, allartwork[art])
def setArtProp(self, listItem, arttype, path):
def setArtProp(self, listItem, arttype, path):
if arttype in (
if arttype in ( 'thumb', 'fanart_image', 'small_poster', 'tiny_poster',
'thumb', 'fanart_image', 'small_poster', 'tiny_poster', 'medium_landscape', 'medium_poster', 'small_fanartimage',
'medium_landscape', 'medium_poster', 'small_fanartimage', 'medium_fanartimage', 'fanart_noindicators'):
'medium_fanartimage', 'fanart_noindicators'):
listItem.setProperty(arttype, path)
listItem.setProperty(arttype, path) else:
else: listItem.setArt({arttype: path})
listItem.setArt({arttype: path})
def setListItem(self, listItem):
def setListItem(self, listItem):
item = self.item
item = self.item itemtype = item['Type']
itemtype = item['Type'] API = self.API
API = self.API people = API.getPeople()
people = API.getPeople() studios = API.getStudios()
studios = API.getStudios()
metadata = {
metadata = {
'title': item.get('Name', "Missing name"),
'title': item.get('Name', "Missing name"), 'year': item.get('ProductionYear'),
'year': item.get('ProductionYear'), 'plot': API.getOverview(),
'plot': API.getOverview(), 'director': people.get('Director'),
'director': people.get('Director'), 'writer': people.get('Writer'),
'writer': people.get('Writer'), 'mpaa': API.getMpaa(),
'mpaa': API.getMpaa(), 'genre': " / ".join(item['Genres']),
'genre': " / ".join(item['Genres']), 'studio': " / ".join(studios),
'studio': " / ".join(studios), 'aired': API.getPremiereDate(),
'aired': API.getPremiereDate(), 'rating': item.get('CommunityRating'),
'rating': item.get('CommunityRating'), 'votes': item.get('VoteCount')
'votes': item.get('VoteCount') }
}
if "Episode" in itemtype:
if "Episode" in itemtype: # Only for tv shows
# Only for tv shows thumbId = item.get('SeriesId')
thumbId = item.get('SeriesId') season = item.get('ParentIndexNumber', -1)
season = item.get('ParentIndexNumber', -1) episode = item.get('IndexNumber', -1)
episode = item.get('IndexNumber', -1) show = item.get('SeriesName', "")
show = item.get('SeriesName', "")
metadata['TVShowTitle'] = show
metadata['TVShowTitle'] = show metadata['season'] = season
metadata['season'] = season metadata['episode'] = episode
metadata['episode'] = episode
listItem.setProperty('IsPlayable', 'true')
listItem.setProperty('IsPlayable', 'true') listItem.setProperty('IsFolder', 'false')
listItem.setProperty('IsFolder', 'false') listItem.setLabel(metadata['title'])
listItem.setLabel(metadata['title'])
listItem.setInfo('video', infoLabels=metadata) listItem.setInfo('video', infoLabels=metadata)