From aa900c6b8891a4a078b9389c063c0058de230dbc Mon Sep 17 00:00:00 2001 From: tomkat83 Date: Sun, 19 Mar 2017 12:14:16 +0100 Subject: [PATCH] Rewire Kodi ListItem stuff --- resources/lib/PKC_listitem.py | 65 +++++++-------- resources/lib/PlexAPI.py | 126 ++++++++++++++---------------- resources/lib/entrypoint.py | 18 ++--- resources/lib/playback_starter.py | 2 - 4 files changed, 101 insertions(+), 110 deletions(-) diff --git a/resources/lib/PKC_listitem.py b/resources/lib/PKC_listitem.py index 2bb92a21..6e16fcb9 100644 --- a/resources/lib/PKC_listitem.py +++ b/resources/lib/PKC_listitem.py @@ -14,18 +14,21 @@ def convert_PKC_to_listitem(PKC_listitem): """ Insert a PKC_listitem and you will receive a valid XBMC listitem """ - listitem = ListItem() - for func, args in PKC_listitem.data.items(): - if isinstance(args, list): - for arg in args: - getattr(listitem, func)(*arg) - elif isinstance(args, dict): - for arg in args.items(): - getattr(listitem, func)(*arg) - elif args is None: - continue - else: - getattr(listitem, func)(args) + data = PKC_listitem.data + log.debug('data is: %s' % data) + listitem = ListItem(label=data.get('label'), + label2=data.get('label2'), + path=data.get('path')) + if data['info']: + listitem.setInfo(**data['info']) + for stream in data['stream_info']: + listitem.addStreamInfo(**stream) + if data['art']: + listitem.setArt(data['art']) + for key, value in data['property'].iteritems(): + listitem.setProperty(key, value) + if data['subtitles']: + listitem.setSubtitles(data['subtitles']) return listitem @@ -38,14 +41,14 @@ class PKC_ListItem(object): """ def __init__(self, label=None, label2=None, path=None): self.data = { - 'addStreamInfo': [], # (type, values: dict { label: value }) - 'setArt': [], # dict: { label: value } - 'setInfo': {}, # type: infoLabel (dict { label: value }) - 'setLabel': label, # string - 'setLabel2': label2, # string - 'setPath': path, # string - 'setProperty': {}, # (key, value) - 'setSubtitles': [], # string + 'stream_info': [], # (type, values: dict { label: value }) + 'art': {}, # dict + 'info': {}, # type: infoLabel (dict { label: value }) + 'label': label, # string + 'label2': label2, # string + 'path': path, # string + 'property': {}, # (key, value) + 'subtitles': [], # strings } def addContextMenuItems(self, items, replaceItems): @@ -87,19 +90,19 @@ class PKC_ListItem(object): - Subtitle Values: - language : string (en) """ - self.data['addStreamInfo'].append((type, values)) + self.data['stream_info'].append({'type': type, 'values': values}) def getLabel(self): """ Returns the listitem label """ - return self.data['setLabel'] + return self.data.get('label') def getLabel2(self): """ Returns the listitem label. """ - return self.data['setLabel2'] + return self.data.get('label2') def getMusicInfoTag(self): """ @@ -118,7 +121,7 @@ class PKC_ListItem(object): 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): """ @@ -172,7 +175,7 @@ class PKC_ListItem(object): - landscape : string - image filename - icon : string - image filename """ - self.data['setArt'].append(values) + self.data['art'].update(values) def setContentLookup(self, enable): """ @@ -270,21 +273,21 @@ class PKC_ListItem(object): - exif : string (See CPictureInfoTag::TranslateString in PictureInfoTag.cpp for valid strings) """ - self.data['setInfo'][type] = infoLabels + self.data['info'] = {'type': type, 'infoLabels': infoLabels} def setLabel(self, label): """ Sets the listitem's label. label : string or unicode - text string. """ - self.data['setLabel'] = label + self.data['label'] = label def setLabel2(self, label): """ Sets the listitem's label2. label : string or unicode - text string. """ - self.data['setLabel2'] = label + self.data['label2'] = label def setMimeType(self, mimetype): """ @@ -303,7 +306,7 @@ class PKC_ListItem(object): *Note, You can use the above as keywords for arguments. """ - self.data['setPath'] = path + self.data['path'] = path 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 information, such as 'WatchedCount' for tvshow items """ - self.data['setProperty'][key] = value + self.data['property'][key] = value def setSubtitles(self, subtitles): """ @@ -331,4 +334,4 @@ class PKC_ListItem(object): - listitem.setSubtitles(['special://temp/example.srt', 'http://example.com/example.srt' ]) """ - self.data['setSubtitles'].extend(([subtitles],)) + self.data['subtitles'].extend(subtitles) diff --git a/resources/lib/PlexAPI.py b/resources/lib/PlexAPI.py index e78621d5..3562f9a4 100644 --- a/resources/lib/PlexAPI.py +++ b/resources/lib/PlexAPI.py @@ -1208,6 +1208,36 @@ class API(): ans = unquote(ans).decode('latin1') 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): """ 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) 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): """ Takes Plex' originallyAvailableAt of the form "yyyy-mm-dd" and returns @@ -2301,7 +2319,24 @@ class API(): date = None 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 """ @@ -2310,63 +2345,21 @@ class API(): listItem = xbmcgui.ListItem(title) else: 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 = { 'date': self.GetKodiPremierDate(), - 'picturepath': path, 'size': long(self.item[0][0].attrib.get('size', 0)), 'exif:width': self.item[0].attrib.get('width', ''), 'exif:height': self.item[0].attrib.get('height', ''), - 'title': title } - listItem.setInfo('pictures', 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.setInfo(type='image', infoLabels=metadata) listItem.setProperty('plot', self.getPlot()) 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 - def _createVideoListItem(self, - listItem=None, - appendShowTitle=False, - appendSxxExx=False): + def __createVideoListItem(self, + listItem=None, + appendShowTitle=False, + appendSxxExx=False): """ Use for video items only 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: listItem = xbmcgui.ListItem(title) - listItem.setProperty('IsPlayable', 'true') + else: + listItem.setLabel(title) # Video items, e.g. movies and episodes or clips people = self.getPeople() @@ -2410,8 +2404,7 @@ class API(): listItem.setProperty('resumetime', str(userdata['Resume'])) listItem.setProperty('totaltime', str(userdata['Runtime'])) - if typus == "episode": - # Only for tv shows + if typus == v.PLEX_TYPE_EPISODE: key, show, season, episode = self.getEpisodeDetails() season = -1 if season is None else int(season) episode = -1 if episode is None else int(episode) @@ -2426,7 +2419,9 @@ class API(): listItem.setArt({'icon': 'DefaultTVShows.png'}) if appendShowTitle is True: 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'}) else: # E.g. clips, trailers, ... @@ -2442,11 +2437,10 @@ class API(): pass # Expensive operation metadata['title'] = title - listItem.setLabel(title) listItem.setInfo('video', infoLabels=metadata) return listItem - def AddStreamInfo(self, listItem): + def add_video_streams(self, listItem): """ Add media stream information to xbmcgui.ListItem """ diff --git a/resources/lib/entrypoint.py b/resources/lib/entrypoint.py index d2e0e77c..97185af4 100644 --- a/resources/lib/entrypoint.py +++ b/resources/lib/entrypoint.py @@ -624,8 +624,6 @@ def getOnDeck(viewid, mediatype, tagname, limit): listitem = api.CreateListItemFromPlexItem( appendShowTitle=appendShowTitle, appendSxxExx=appendSxxExx) - api.AddStreamInfo(listitem) - api.set_listitem_artwork(listitem) if directpaths: url = api.getFilePath() else: @@ -815,10 +813,10 @@ def browse_plex(key=None, plex_section_id=None): albums = False musicvideos = False for item in xml: - typus = item.attrib.get('type') if item.tag == 'Directory': __build_folder(item, plex_section_id=plex_section_id) else: + typus = item.attrib.get('type') __build_item(item) if typus == v.PLEX_TYPE_PHOTO: photos = True @@ -905,11 +903,6 @@ def __build_folder(xml_element, plex_section_id=None): def __build_item(xml_element): api = API(xml_element) listitem = api.CreateListItemFromPlexItem() - try: - api.AddStreamInfo(listitem) - except: - pass - api.set_listitem_artwork(listitem) if (api.getKey().startswith('/system/services') or api.getKey().startswith('http')): params = { @@ -917,14 +910,17 @@ def __build_item(xml_element): 'key': xml_element.attrib.get('key'), '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: params = { + 'mode': 'play', 'filename': api.getKey(), 'id': api.getRatingKey(), - 'dbid': listitem.getProperty('dbid'), - 'mode': "play" + 'dbid': listitem.getProperty('dbid') } - url = "plugin://%s?%s" % (v.ADDON_ID, urlencode(params)) + url = "plugin://%s?%s" % (v.ADDON_ID, urlencode(params)) xbmcplugin.addDirectoryItem(handle=HANDLE, url=url, listitem=listitem) diff --git a/resources/lib/playback_starter.py b/resources/lib/playback_starter.py index f8883c07..d59d98e9 100644 --- a/resources/lib/playback_starter.py +++ b/resources/lib/playback_starter.py @@ -55,8 +55,6 @@ class Playback_Starter(Thread): result = Playback_Successful() listitem = PKC_ListItem() listitem = api.CreateListItemFromPlexItem(listitem) - api.AddStreamInfo(listitem) - api.set_listitem_artwork(listitem) result.listitem = listitem else: # Video and Music