diff --git a/addon.xml b/addon.xml index e6348da3..5bf25694 100644 --- a/addon.xml +++ b/addon.xml @@ -1,5 +1,5 @@ - + @@ -83,7 +83,10 @@ Natūralioji „Plex“ integracija į „Kodi“ Prijunkite „Kodi“ prie „Plex Medija Serverio“. Šiame papildinyje daroma prielaida, kad valdote visus savo vaizdo įrašus naudodami „Plex“ (ir nė vieno su „Kodi“). Galite prarasti jau saugomus „Kodi“ vaizdo įrašų ir muzikos duomenų bazių duomenis (kadangi šis papildinys juos tiesiogiai pakeičia). Naudokite savo pačių rizika! Naudokite savo pačių rizika - version 2.12.9: + version 2.12.10: +- Fix pictures from Plex picture libraries not working/displaying + +version 2.12.9: - Fix Local variable 'user' referenced before assignement version 2.12.8: diff --git a/changelog.txt b/changelog.txt index 5322b44f..e508d772 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,6 @@ +version 2.12.10: +- Fix pictures from Plex picture libraries not working/displaying + version 2.12.9: - Fix Local variable 'user' referenced before assignement diff --git a/resources/lib/plex_api/media.py b/resources/lib/plex_api/media.py index e6eb7a59..7ddb14ca 100644 --- a/resources/lib/plex_api/media.py +++ b/resources/lib/plex_api/media.py @@ -62,6 +62,25 @@ class Media(object): answ['bitDepth'] = None return answ + def picture_codec(self): + """ + Returns the exif metadata of pictures. This does NOT seem to be used + reliably by Kodi skins! (e.g. not at all) + """ + return { + 'exif:CameraMake': self.xml[0].get('make'), # e.g. 'Canon' + 'exif:CameraModel': self.xml[0].get('model'), # e.g. 'Canon XYZ' + 'exif:DateTime': self.xml.get('originallyAvailableAt', '').replace('-', ':') or None, # e.g. '2017-11-05' + 'exif:Height': self.xml[0].get('height'), # e.g. '2160' + 'exif:Width': self.xml[0].get('width'), # e.g. '3240' + 'exif:Orientation': self.xml[0][self.part].get('orientation'), # e.g. '1' + 'exif:FocalLength': self.xml[0].get('focalLength'), # TO BE VALIDATED + 'exif:ExposureTime': self.xml[0].get('exposure'), # e.g. '1/1000' + 'exif:ApertureFNumber': self.xml[0].get('aperture'), # e.g. 'f/5.0' + 'exif:ISOequivalent': self.xml[0].get('iso'), # e.g. '1600' + # missing on Kodi side: lens, e.g. "EF50mm f/1.8 II" + } + def mediastreams(self): """ Returns the media streams for metadata purposes diff --git a/resources/lib/widgets.py b/resources/lib/widgets.py index b9c779a2..837ba719 100644 --- a/resources/lib/widgets.py +++ b/resources/lib/widgets.py @@ -136,74 +136,84 @@ def _generate_content(api): # other fields - let's use the PMS answer to be safe # See https://github.com/croneter/PlexKodiConnect/issues/1129 if not api.kodi_id or 'title' not in item: - cast = [{ - 'name': x[0], - 'thumbnail': x[1], - 'role': x[2], - 'order': x[3], - } for x in api.people()['actor']] - item = { - 'cast': cast, - 'country': api.countries(), - 'dateadded': api.date_created(), # e.g '2019-01-03 19:40:59' - 'director': api.directors(), # list of [str] - 'duration': api.runtime(), - 'episode': api.index(), - # 'file': '', # e.g. 'videodb://tvshows/titles/20' - 'genre': api.genres(), - # 'imdbnumber': '', # e.g.'341663' - 'label': api.title(), # e.g. '1x05. Category 55 Emergency Doomsday Crisis' - 'lastplayed': api.lastplayed(), # e.g. '2019-01-04 16:05:03' - 'mpaa': api.content_rating(), # e.g. 'TV-MA' - 'originaltitle': '', # e.g. 'Titans (2018)' - 'playcount': api.viewcount(), # [int] - 'plot': api.plot(), # [str] - 'plotoutline': api.tagline(), - 'premiered': api.premiere_date(), # '2018-10-12' - 'rating': api.rating(), # [float] - 'season': api.season_number(), - 'sorttitle': api.sorttitle(), # 'Titans (2018)' - 'studio': api.studios(), - 'tag': [], # List of tags this item belongs to - 'tagline': api.tagline(), - 'thumbnail': '', # e.g. 'image://https%3a%2f%2fassets.tv' - 'title': api.title(), # 'Titans (2018)' - 'type': api.kodi_type, - 'trailer': api.trailer(), - 'tvshowtitle': api.show_title(), - 'uniqueid': { - 'imdbnumber': api.guids.get('imdb') or '', - 'tvdb_id': api.guids.get('tvdb') or '', - 'tmdb_id': api.guids.get('tmdb') or '' - }, - 'votes': '0', # [str]! - 'writer': api.writers(), # list of [str] - 'year': api.year(), # [int] - } - - if plex_type in (v.PLEX_TYPE_EPISODE, v.PLEX_TYPE_SEASON, v.PLEX_TYPE_SHOW): - leaves = api.leave_count() - if leaves: - item['extraproperties'] = leaves + if api.plex_type == v.PLEX_TYPE_PHOTO: + item = { + 'title': api.title(), + 'label': api.title(), + 'type': api.kodi_type, + 'dateadded': api.date_created(), # e.g '2019-01-03 19:40:59' + 'lastplayed': api.lastplayed(), # e.g. '2019-01-04 16:05:03' + 'playcount': api.viewcount(), + } + item.update(api.picture_codec()) + else: + cast = [{ + 'name': x[0], + 'thumbnail': x[1], + 'role': x[2], + 'order': x[3], + } for x in api.people()['actor']] + item = { + 'cast': cast, + 'country': api.countries(), + 'dateadded': api.date_created(), # e.g '2019-01-03 19:40:59' + 'director': api.directors(), # list of [str] + 'duration': api.runtime(), + 'episode': api.index(), + # 'file': '', # e.g. 'videodb://tvshows/titles/20' + 'genre': api.genres(), + # 'imdbnumber': '', # e.g.'341663' + 'label': api.title(), # e.g. '1x05. Category 55 Emergency Doomsday Crisis' + 'lastplayed': api.lastplayed(), # e.g. '2019-01-04 16:05:03' + 'mpaa': api.content_rating(), # e.g. 'TV-MA' + 'originaltitle': '', # e.g. 'Titans (2018)' + 'playcount': api.viewcount(), # [int] + 'plot': api.plot(), # [str] + 'plotoutline': api.tagline(), + 'premiered': api.premiere_date(), # '2018-10-12' + 'rating': api.rating(), # [float] + 'season': api.season_number(), + 'sorttitle': api.sorttitle(), # 'Titans (2018)' + 'studio': api.studios(), + 'tag': [], # List of tags this item belongs to + 'tagline': api.tagline(), + 'thumbnail': '', # e.g. 'image://https%3a%2f%2fassets.tv' + 'title': api.title(), # 'Titans (2018)' + 'type': api.kodi_type, + 'trailer': api.trailer(), + 'tvshowtitle': api.show_title(), + 'uniqueid': { + 'imdbnumber': api.guids.get('imdb') or '', + 'tvdb_id': api.guids.get('tvdb') or '', + 'tmdb_id': api.guids.get('tmdb') or '' + }, + 'votes': '0', # [str]! + 'writer': api.writers(), # list of [str] + 'year': api.year(), # [int] + } + # Add all info for e.g. video and audio streams + item['streamdetails'] = api.mediastreams() + # Cleanup required due to the way metadatautils works + if not item['lastplayed']: + del item['lastplayed'] + for stream in item['streamdetails']['video']: + stream['height'] = utils.cast(int, stream['height']) + stream['width'] = utils.cast(int, stream['width']) + stream['aspect'] = utils.cast(float, stream['aspect']) + item['streamdetails']['subtitle'] = [{'language': x} for x in item['streamdetails']['subtitle']] + # Resume point + resume = api.resume_point() + if resume: + item['resume'] = { + 'position': resume, + 'total': api.runtime() + } + if plex_type in (v.PLEX_TYPE_EPISODE, v.PLEX_TYPE_SEASON, v.PLEX_TYPE_SHOW): + leaves = api.leave_count() + if leaves: + item['extraproperties'] = leaves # Add all the artwork we can item['art'] = api.artwork(full_artwork=True) - # Add all info for e.g. video and audio streams - item['streamdetails'] = api.mediastreams() - # Cleanup required due to the way metadatautils works - if not item['lastplayed']: - del item['lastplayed'] - for stream in item['streamdetails']['video']: - stream['height'] = utils.cast(int, stream['height']) - stream['width'] = utils.cast(int, stream['width']) - stream['aspect'] = utils.cast(float, stream['aspect']) - item['streamdetails']['subtitle'] = [{'language': x} for x in item['streamdetails']['subtitle']] - # Resume point - resume = api.resume_point() - if resume: - item['resume'] = { - 'position': resume, - 'total': api.runtime() - } item['icon'] = v.ICON_FROM_PLEXTYPE[plex_type] # Some customization @@ -472,16 +482,18 @@ def create_listitem(item, as_tuple=True, offscreen=True, elif "plugin://script.skin.helper" not in item['file']: liz.setProperty('IsPlayable', 'true') - nodetype = "Video" if item["type"] in ["song", "album", "artist"]: - nodetype = "Music" + nodetype = "music" + elif item['type'] == 'photo': + nodetype = 'pictures' + else: + nodetype = 'video' # extra properties for key, value in item["extraproperties"].iteritems(): liz.setProperty(key, value) - # video infolabels - if nodetype == "Video": + if nodetype == 'video': infolabels = { "title": item.get("title"), "size": item.get("size"), @@ -532,8 +544,7 @@ def create_listitem(item, as_tuple=True, offscreen=True, if "date" in item: infolabels["date"] = item["date"] - # music infolabels - else: + elif nodetype == 'music': infolabels = { "title": item.get("title"), "size": item.get("size"), @@ -553,12 +564,18 @@ def create_listitem(item, as_tuple=True, offscreen=True, if "lastplayed" in item: infolabels["lastplayed"] = item["lastplayed"] + else: + # Pictures + infolabels = { + "title": item.get("title"), + 'picturepath': item['file'] + } # setting the dbtype and dbid is supported from kodi krypton and up # PKC hack: ignore empty type if item["type"] not in ["recording", "channel", "favourite", ""]: infolabels["mediatype"] = item["type"] # setting the dbid on music items is not supported ? - if nodetype == "Video" and "DBID" in item["extraproperties"]: + if nodetype == "video" and "DBID" in item["extraproperties"]: infolabels["dbid"] = item["extraproperties"]["DBID"] if "lastplayed" in item: