Rewire Kodi ListItem stuff
This commit is contained in:
parent
264782c787
commit
aa900c6b88
4 changed files with 101 additions and 110 deletions
|
@ -14,18 +14,21 @@ def convert_PKC_to_listitem(PKC_listitem):
|
||||||
"""
|
"""
|
||||||
Insert a PKC_listitem and you will receive a valid XBMC listitem
|
Insert a PKC_listitem and you will receive a valid XBMC listitem
|
||||||
"""
|
"""
|
||||||
listitem = ListItem()
|
data = PKC_listitem.data
|
||||||
for func, args in PKC_listitem.data.items():
|
log.debug('data is: %s' % data)
|
||||||
if isinstance(args, list):
|
listitem = ListItem(label=data.get('label'),
|
||||||
for arg in args:
|
label2=data.get('label2'),
|
||||||
getattr(listitem, func)(*arg)
|
path=data.get('path'))
|
||||||
elif isinstance(args, dict):
|
if data['info']:
|
||||||
for arg in args.items():
|
listitem.setInfo(**data['info'])
|
||||||
getattr(listitem, func)(*arg)
|
for stream in data['stream_info']:
|
||||||
elif args is None:
|
listitem.addStreamInfo(**stream)
|
||||||
continue
|
if data['art']:
|
||||||
else:
|
listitem.setArt(data['art'])
|
||||||
getattr(listitem, func)(args)
|
for key, value in data['property'].iteritems():
|
||||||
|
listitem.setProperty(key, value)
|
||||||
|
if data['subtitles']:
|
||||||
|
listitem.setSubtitles(data['subtitles'])
|
||||||
return listitem
|
return listitem
|
||||||
|
|
||||||
|
|
||||||
|
@ -38,14 +41,14 @@ class PKC_ListItem(object):
|
||||||
"""
|
"""
|
||||||
def __init__(self, label=None, label2=None, path=None):
|
def __init__(self, label=None, label2=None, path=None):
|
||||||
self.data = {
|
self.data = {
|
||||||
'addStreamInfo': [], # (type, values: dict { label: value })
|
'stream_info': [], # (type, values: dict { label: value })
|
||||||
'setArt': [], # dict: { label: value }
|
'art': {}, # dict
|
||||||
'setInfo': {}, # type: infoLabel (dict { label: value })
|
'info': {}, # type: infoLabel (dict { label: value })
|
||||||
'setLabel': label, # string
|
'label': label, # string
|
||||||
'setLabel2': label2, # string
|
'label2': label2, # string
|
||||||
'setPath': path, # string
|
'path': path, # string
|
||||||
'setProperty': {}, # (key, value)
|
'property': {}, # (key, value)
|
||||||
'setSubtitles': [], # string
|
'subtitles': [], # strings
|
||||||
}
|
}
|
||||||
|
|
||||||
def addContextMenuItems(self, items, replaceItems):
|
def addContextMenuItems(self, items, replaceItems):
|
||||||
|
@ -87,19 +90,19 @@ class PKC_ListItem(object):
|
||||||
- Subtitle Values:
|
- Subtitle Values:
|
||||||
- language : string (en)
|
- language : string (en)
|
||||||
"""
|
"""
|
||||||
self.data['addStreamInfo'].append((type, values))
|
self.data['stream_info'].append({'type': type, 'values': values})
|
||||||
|
|
||||||
def getLabel(self):
|
def getLabel(self):
|
||||||
"""
|
"""
|
||||||
Returns the listitem label
|
Returns the listitem label
|
||||||
"""
|
"""
|
||||||
return self.data['setLabel']
|
return self.data.get('label')
|
||||||
|
|
||||||
def getLabel2(self):
|
def getLabel2(self):
|
||||||
"""
|
"""
|
||||||
Returns the listitem label.
|
Returns the listitem label.
|
||||||
"""
|
"""
|
||||||
return self.data['setLabel2']
|
return self.data.get('label2')
|
||||||
|
|
||||||
def getMusicInfoTag(self):
|
def getMusicInfoTag(self):
|
||||||
"""
|
"""
|
||||||
|
@ -118,7 +121,7 @@ class PKC_ListItem(object):
|
||||||
|
|
||||||
Once you use a keyword, all following arguments require the keyword.
|
Once you use a keyword, all following arguments require the keyword.
|
||||||
"""
|
"""
|
||||||
return self.data['setProperty'].get(key)
|
return self.data['property'].get(key)
|
||||||
|
|
||||||
def getVideoInfoTag(self):
|
def getVideoInfoTag(self):
|
||||||
"""
|
"""
|
||||||
|
@ -172,7 +175,7 @@ class PKC_ListItem(object):
|
||||||
- landscape : string - image filename
|
- landscape : string - image filename
|
||||||
- icon : string - image filename
|
- icon : string - image filename
|
||||||
"""
|
"""
|
||||||
self.data['setArt'].append(values)
|
self.data['art'].update(values)
|
||||||
|
|
||||||
def setContentLookup(self, enable):
|
def setContentLookup(self, enable):
|
||||||
"""
|
"""
|
||||||
|
@ -270,21 +273,21 @@ class PKC_ListItem(object):
|
||||||
- exif : string (See CPictureInfoTag::TranslateString in
|
- exif : string (See CPictureInfoTag::TranslateString in
|
||||||
PictureInfoTag.cpp for valid strings)
|
PictureInfoTag.cpp for valid strings)
|
||||||
"""
|
"""
|
||||||
self.data['setInfo'][type] = infoLabels
|
self.data['info'] = {'type': type, 'infoLabels': infoLabels}
|
||||||
|
|
||||||
def setLabel(self, label):
|
def setLabel(self, label):
|
||||||
"""
|
"""
|
||||||
Sets the listitem's label.
|
Sets the listitem's label.
|
||||||
label : string or unicode - text string.
|
label : string or unicode - text string.
|
||||||
"""
|
"""
|
||||||
self.data['setLabel'] = label
|
self.data['label'] = label
|
||||||
|
|
||||||
def setLabel2(self, label):
|
def setLabel2(self, label):
|
||||||
"""
|
"""
|
||||||
Sets the listitem's label2.
|
Sets the listitem's label2.
|
||||||
label : string or unicode - text string.
|
label : string or unicode - text string.
|
||||||
"""
|
"""
|
||||||
self.data['setLabel2'] = label
|
self.data['label2'] = label
|
||||||
|
|
||||||
def setMimeType(self, mimetype):
|
def setMimeType(self, mimetype):
|
||||||
"""
|
"""
|
||||||
|
@ -303,7 +306,7 @@ class PKC_ListItem(object):
|
||||||
|
|
||||||
*Note, You can use the above as keywords for arguments.
|
*Note, You can use the above as keywords for arguments.
|
||||||
"""
|
"""
|
||||||
self.data['setPath'] = path
|
self.data['path'] = path
|
||||||
|
|
||||||
def setProperty(self, key, value):
|
def setProperty(self, key, value):
|
||||||
"""
|
"""
|
||||||
|
@ -321,7 +324,7 @@ class PKC_ListItem(object):
|
||||||
start playback of an item. Others may be used in the skin to add extra
|
start playback of an item. Others may be used in the skin to add extra
|
||||||
information, such as 'WatchedCount' for tvshow items
|
information, such as 'WatchedCount' for tvshow items
|
||||||
"""
|
"""
|
||||||
self.data['setProperty'][key] = value
|
self.data['property'][key] = value
|
||||||
|
|
||||||
def setSubtitles(self, subtitles):
|
def setSubtitles(self, subtitles):
|
||||||
"""
|
"""
|
||||||
|
@ -331,4 +334,4 @@ class PKC_ListItem(object):
|
||||||
- listitem.setSubtitles(['special://temp/example.srt',
|
- listitem.setSubtitles(['special://temp/example.srt',
|
||||||
'http://example.com/example.srt' ])
|
'http://example.com/example.srt' ])
|
||||||
"""
|
"""
|
||||||
self.data['setSubtitles'].extend(([subtitles],))
|
self.data['subtitles'].extend(subtitles)
|
||||||
|
|
|
@ -1208,6 +1208,36 @@ class API():
|
||||||
ans = unquote(ans).decode('latin1')
|
ans = unquote(ans).decode('latin1')
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
|
def get_picture_path(self):
|
||||||
|
"""
|
||||||
|
Returns the item's picture path (transcode, if necessary) as string
|
||||||
|
"""
|
||||||
|
extension = self.item[0][0].attrib['key'][self.item[0][0].attrib['key'].rfind('.'):].lower()
|
||||||
|
if (window('plex_force_transcode_pix') == 'true' or
|
||||||
|
extension not in v.KODI_SUPPORTED_IMAGES):
|
||||||
|
# Let Plex transcode
|
||||||
|
# max width/height supported by plex image transcoder is 1920x1080
|
||||||
|
path = self.server + PlexAPI().getTranscodeImagePath(
|
||||||
|
self.item[0][0].attrib.get('key'),
|
||||||
|
window('pms_token'),
|
||||||
|
"%s%s" % (self.server, self.item[0][0].attrib.get('key')),
|
||||||
|
1920,
|
||||||
|
1080)
|
||||||
|
else:
|
||||||
|
# Don't transcode
|
||||||
|
if window('useDirectPaths') == 'true':
|
||||||
|
# Addon Mode. Just give the path of the file to Kodi
|
||||||
|
path = self.addPlexCredentialsToUrl(
|
||||||
|
'%s%s' % (window('pms_server'),
|
||||||
|
self.item[0][0].attrib['key']))
|
||||||
|
else:
|
||||||
|
# Native direct paths
|
||||||
|
path = self.validatePlayurl(
|
||||||
|
self.getFilePath(forceFirstMediaStream=True),
|
||||||
|
'photo')
|
||||||
|
path = tryEncode(path)
|
||||||
|
return path
|
||||||
|
|
||||||
def getTVShowPath(self):
|
def getTVShowPath(self):
|
||||||
"""
|
"""
|
||||||
Returns the direct path to the TV show, e.g. '\\NAS\tv\series'
|
Returns the direct path to the TV show, e.g. '\\NAS\tv\series'
|
||||||
|
@ -2275,18 +2305,6 @@ class API():
|
||||||
log.info('Found external subs: %s' % externalsubs)
|
log.info('Found external subs: %s' % externalsubs)
|
||||||
return externalsubs
|
return externalsubs
|
||||||
|
|
||||||
def CreateListItemFromPlexItem(self,
|
|
||||||
listItem=None,
|
|
||||||
appendShowTitle=False,
|
|
||||||
appendSxxExx=False):
|
|
||||||
if self.getType() == 'photo':
|
|
||||||
listItem = self._createPhotoListItem(listItem)
|
|
||||||
else:
|
|
||||||
listItem = self._createVideoListItem(listItem,
|
|
||||||
appendShowTitle,
|
|
||||||
appendSxxExx)
|
|
||||||
return listItem
|
|
||||||
|
|
||||||
def GetKodiPremierDate(self):
|
def GetKodiPremierDate(self):
|
||||||
"""
|
"""
|
||||||
Takes Plex' originallyAvailableAt of the form "yyyy-mm-dd" and returns
|
Takes Plex' originallyAvailableAt of the form "yyyy-mm-dd" and returns
|
||||||
|
@ -2301,7 +2319,24 @@ class API():
|
||||||
date = None
|
date = None
|
||||||
return date
|
return date
|
||||||
|
|
||||||
def _createPhotoListItem(self, listItem=None):
|
def CreateListItemFromPlexItem(self,
|
||||||
|
listItem=None,
|
||||||
|
appendShowTitle=False,
|
||||||
|
appendSxxExx=False):
|
||||||
|
if self.getType() == v.PLEX_TYPE_PHOTO:
|
||||||
|
listItem = self.__createPhotoListItem(listItem)
|
||||||
|
# Only set the bare minimum of artwork
|
||||||
|
listItem.setArt({'icon': 'DefaultPicture.png',
|
||||||
|
'fanart': self.__getOneArtwork('thumb')})
|
||||||
|
else:
|
||||||
|
listItem = self.__createVideoListItem(listItem,
|
||||||
|
appendShowTitle,
|
||||||
|
appendSxxExx)
|
||||||
|
self.add_video_streams(listItem)
|
||||||
|
self.set_listitem_artwork(listItem)
|
||||||
|
return listItem
|
||||||
|
|
||||||
|
def __createPhotoListItem(self, listItem=None):
|
||||||
"""
|
"""
|
||||||
Use for photo items only
|
Use for photo items only
|
||||||
"""
|
"""
|
||||||
|
@ -2310,63 +2345,21 @@ class API():
|
||||||
listItem = xbmcgui.ListItem(title)
|
listItem = xbmcgui.ListItem(title)
|
||||||
else:
|
else:
|
||||||
listItem.setLabel(title)
|
listItem.setLabel(title)
|
||||||
listItem.setProperty('IsPlayable', 'true')
|
|
||||||
extension = self.item[0][0].attrib['key'][self.item[0][0].attrib['key'].rfind('.'):].lower()
|
|
||||||
if (window('plex_force_transcode_pix') == 'true' or
|
|
||||||
extension not in v.KODI_SUPPORTED_IMAGES):
|
|
||||||
# Let Plex transcode
|
|
||||||
# max width/height supported by plex image transcoder is 1920x1080
|
|
||||||
path = self.server + PlexAPI().getTranscodeImagePath(
|
|
||||||
self.item[0][0].attrib.get('key'),
|
|
||||||
window('pms_token'),
|
|
||||||
"%s%s" % (self.server, self.item[0][0].attrib.get('key')),
|
|
||||||
1920,
|
|
||||||
1080)
|
|
||||||
else:
|
|
||||||
# Don't transcode
|
|
||||||
if window('useDirectPaths') == 'true':
|
|
||||||
# Addon Mode. Just give the path of the file to Kodi
|
|
||||||
path = self.addPlexCredentialsToUrl(
|
|
||||||
'%s%s' % (window('pms_server'),
|
|
||||||
self.item[0][0].attrib['key']))
|
|
||||||
else:
|
|
||||||
# Native direct paths
|
|
||||||
path = self.validatePlayurl(
|
|
||||||
self.getFilePath(forceFirstMediaStream=True),
|
|
||||||
'photo')
|
|
||||||
|
|
||||||
path = tryEncode(path)
|
|
||||||
metadata = {
|
metadata = {
|
||||||
'date': self.GetKodiPremierDate(),
|
'date': self.GetKodiPremierDate(),
|
||||||
'picturepath': path,
|
|
||||||
'size': long(self.item[0][0].attrib.get('size', 0)),
|
'size': long(self.item[0][0].attrib.get('size', 0)),
|
||||||
'exif:width': self.item[0].attrib.get('width', ''),
|
'exif:width': self.item[0].attrib.get('width', ''),
|
||||||
'exif:height': self.item[0].attrib.get('height', ''),
|
'exif:height': self.item[0].attrib.get('height', ''),
|
||||||
'title': title
|
|
||||||
}
|
}
|
||||||
listItem.setInfo('pictures', infoLabels=metadata)
|
listItem.setInfo(type='image', infoLabels=metadata)
|
||||||
try:
|
|
||||||
if int(metadata['exif:width']) > int(metadata['exif:height']):
|
|
||||||
# add image as fanart for use with skinhelper auto thumb/
|
|
||||||
# backgrund creation
|
|
||||||
listItem.setArt({'fanart': path})
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
# Stuff that we CANNOT set with listItem.setInfo
|
|
||||||
listItem.setProperty('path', path)
|
|
||||||
listItem.setProperty('plot', self.getPlot())
|
listItem.setProperty('plot', self.getPlot())
|
||||||
listItem.setProperty('plexid', self.getRatingKey())
|
listItem.setProperty('plexid', self.getRatingKey())
|
||||||
# We do NOT set these props
|
|
||||||
# listItem.setProperty('isPlayable', 'true')
|
|
||||||
# listItem.setProperty('isFolder', 'true')
|
|
||||||
# Further stuff
|
|
||||||
listItem.setArt({'icon': 'DefaultPicture.png'})
|
|
||||||
return listItem
|
return listItem
|
||||||
|
|
||||||
def _createVideoListItem(self,
|
def __createVideoListItem(self,
|
||||||
listItem=None,
|
listItem=None,
|
||||||
appendShowTitle=False,
|
appendShowTitle=False,
|
||||||
appendSxxExx=False):
|
appendSxxExx=False):
|
||||||
"""
|
"""
|
||||||
Use for video items only
|
Use for video items only
|
||||||
Call on a child level of PMS xml response (e.g. in a for loop)
|
Call on a child level of PMS xml response (e.g. in a for loop)
|
||||||
|
@ -2383,7 +2376,8 @@ class API():
|
||||||
|
|
||||||
if listItem is None:
|
if listItem is None:
|
||||||
listItem = xbmcgui.ListItem(title)
|
listItem = xbmcgui.ListItem(title)
|
||||||
listItem.setProperty('IsPlayable', 'true')
|
else:
|
||||||
|
listItem.setLabel(title)
|
||||||
|
|
||||||
# Video items, e.g. movies and episodes or clips
|
# Video items, e.g. movies and episodes or clips
|
||||||
people = self.getPeople()
|
people = self.getPeople()
|
||||||
|
@ -2410,8 +2404,7 @@ class API():
|
||||||
listItem.setProperty('resumetime', str(userdata['Resume']))
|
listItem.setProperty('resumetime', str(userdata['Resume']))
|
||||||
listItem.setProperty('totaltime', str(userdata['Runtime']))
|
listItem.setProperty('totaltime', str(userdata['Runtime']))
|
||||||
|
|
||||||
if typus == "episode":
|
if typus == v.PLEX_TYPE_EPISODE:
|
||||||
# Only for tv shows
|
|
||||||
key, show, season, episode = self.getEpisodeDetails()
|
key, show, season, episode = self.getEpisodeDetails()
|
||||||
season = -1 if season is None else int(season)
|
season = -1 if season is None else int(season)
|
||||||
episode = -1 if episode is None else int(episode)
|
episode = -1 if episode is None else int(episode)
|
||||||
|
@ -2426,7 +2419,9 @@ class API():
|
||||||
listItem.setArt({'icon': 'DefaultTVShows.png'})
|
listItem.setArt({'icon': 'DefaultTVShows.png'})
|
||||||
if appendShowTitle is True:
|
if appendShowTitle is True:
|
||||||
title = "%s - %s " % (show, title)
|
title = "%s - %s " % (show, title)
|
||||||
elif typus == "movie":
|
if appendShowTitle or appendSxxExx:
|
||||||
|
listItem.setLabel(title)
|
||||||
|
elif typus == v.PLEX_TYPE_MOVIE:
|
||||||
listItem.setArt({'icon': 'DefaultMovies.png'})
|
listItem.setArt({'icon': 'DefaultMovies.png'})
|
||||||
else:
|
else:
|
||||||
# E.g. clips, trailers, ...
|
# E.g. clips, trailers, ...
|
||||||
|
@ -2442,11 +2437,10 @@ class API():
|
||||||
pass
|
pass
|
||||||
# Expensive operation
|
# Expensive operation
|
||||||
metadata['title'] = title
|
metadata['title'] = title
|
||||||
listItem.setLabel(title)
|
|
||||||
listItem.setInfo('video', infoLabels=metadata)
|
listItem.setInfo('video', infoLabels=metadata)
|
||||||
return listItem
|
return listItem
|
||||||
|
|
||||||
def AddStreamInfo(self, listItem):
|
def add_video_streams(self, listItem):
|
||||||
"""
|
"""
|
||||||
Add media stream information to xbmcgui.ListItem
|
Add media stream information to xbmcgui.ListItem
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -624,8 +624,6 @@ def getOnDeck(viewid, mediatype, tagname, limit):
|
||||||
listitem = api.CreateListItemFromPlexItem(
|
listitem = api.CreateListItemFromPlexItem(
|
||||||
appendShowTitle=appendShowTitle,
|
appendShowTitle=appendShowTitle,
|
||||||
appendSxxExx=appendSxxExx)
|
appendSxxExx=appendSxxExx)
|
||||||
api.AddStreamInfo(listitem)
|
|
||||||
api.set_listitem_artwork(listitem)
|
|
||||||
if directpaths:
|
if directpaths:
|
||||||
url = api.getFilePath()
|
url = api.getFilePath()
|
||||||
else:
|
else:
|
||||||
|
@ -815,10 +813,10 @@ def browse_plex(key=None, plex_section_id=None):
|
||||||
albums = False
|
albums = False
|
||||||
musicvideos = False
|
musicvideos = False
|
||||||
for item in xml:
|
for item in xml:
|
||||||
typus = item.attrib.get('type')
|
|
||||||
if item.tag == 'Directory':
|
if item.tag == 'Directory':
|
||||||
__build_folder(item, plex_section_id=plex_section_id)
|
__build_folder(item, plex_section_id=plex_section_id)
|
||||||
else:
|
else:
|
||||||
|
typus = item.attrib.get('type')
|
||||||
__build_item(item)
|
__build_item(item)
|
||||||
if typus == v.PLEX_TYPE_PHOTO:
|
if typus == v.PLEX_TYPE_PHOTO:
|
||||||
photos = True
|
photos = True
|
||||||
|
@ -905,11 +903,6 @@ def __build_folder(xml_element, plex_section_id=None):
|
||||||
def __build_item(xml_element):
|
def __build_item(xml_element):
|
||||||
api = API(xml_element)
|
api = API(xml_element)
|
||||||
listitem = api.CreateListItemFromPlexItem()
|
listitem = api.CreateListItemFromPlexItem()
|
||||||
try:
|
|
||||||
api.AddStreamInfo(listitem)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
api.set_listitem_artwork(listitem)
|
|
||||||
if (api.getKey().startswith('/system/services') or
|
if (api.getKey().startswith('/system/services') or
|
||||||
api.getKey().startswith('http')):
|
api.getKey().startswith('http')):
|
||||||
params = {
|
params = {
|
||||||
|
@ -917,14 +910,17 @@ def __build_item(xml_element):
|
||||||
'key': xml_element.attrib.get('key'),
|
'key': xml_element.attrib.get('key'),
|
||||||
'view_offset': xml_element.attrib.get('viewOffset', '0'),
|
'view_offset': xml_element.attrib.get('viewOffset', '0'),
|
||||||
}
|
}
|
||||||
|
url = "plugin://%s?%s" % (v.ADDON_ID, urlencode(params))
|
||||||
|
elif api.getType() == v.PLEX_TYPE_PHOTO:
|
||||||
|
url = api.get_picture_path()
|
||||||
else:
|
else:
|
||||||
params = {
|
params = {
|
||||||
|
'mode': 'play',
|
||||||
'filename': api.getKey(),
|
'filename': api.getKey(),
|
||||||
'id': api.getRatingKey(),
|
'id': api.getRatingKey(),
|
||||||
'dbid': listitem.getProperty('dbid'),
|
'dbid': listitem.getProperty('dbid')
|
||||||
'mode': "play"
|
|
||||||
}
|
}
|
||||||
url = "plugin://%s?%s" % (v.ADDON_ID, urlencode(params))
|
url = "plugin://%s?%s" % (v.ADDON_ID, urlencode(params))
|
||||||
xbmcplugin.addDirectoryItem(handle=HANDLE,
|
xbmcplugin.addDirectoryItem(handle=HANDLE,
|
||||||
url=url,
|
url=url,
|
||||||
listitem=listitem)
|
listitem=listitem)
|
||||||
|
|
|
@ -55,8 +55,6 @@ class Playback_Starter(Thread):
|
||||||
result = Playback_Successful()
|
result = Playback_Successful()
|
||||||
listitem = PKC_ListItem()
|
listitem = PKC_ListItem()
|
||||||
listitem = api.CreateListItemFromPlexItem(listitem)
|
listitem = api.CreateListItemFromPlexItem(listitem)
|
||||||
api.AddStreamInfo(listitem)
|
|
||||||
api.set_listitem_artwork(listitem)
|
|
||||||
result.listitem = listitem
|
result.listitem = listitem
|
||||||
else:
|
else:
|
||||||
# Video and Music
|
# Video and Music
|
||||||
|
|
Loading…
Reference in a new issue