Overhaul PlexAPI. Only using XMLs now, no JSONs

This commit is contained in:
tomkat83 2016-02-01 10:33:33 +01:00
parent dc44f1a879
commit fa0003a5eb
6 changed files with 175 additions and 330 deletions

View file

@ -769,13 +769,12 @@ class PlexAPI():
XML = self.getXMLFromPMS(PMS['baseURL'],PMS['path'],PMS['options'],PMS['token'])
queue.put( (PMS['data'], XML) )
def getXArgsDeviceInfo(self, options={}, JSON=False):
def getXArgsDeviceInfo(self, options={}):
"""
Returns a dictionary that can be used as headers for GET and POST
requests. An authentication option is NOT yet added.
Inputs:
JSON=True will enforce a JSON answer
options: dictionary of options that will override the
standard header options otherwise set.
Output:
@ -800,8 +799,6 @@ class PlexAPI():
if self.token:
xargs['X-Plex-Token'] = self.token
if JSON:
xargs['Accept'] = 'application/json'
if options:
xargs.update(options)
return xargs
@ -1381,8 +1378,6 @@ class API():
self.server = utils.window('emby_server%s' % self.userId)
self.token = utils.window('emby_accessToken%s' % self.userId)
self.jumpback = int(utils.settings('resumeJumpBack'))
def setPartNumber(self, number=0):
"""
Sets the part number to work with (used to deal with Movie with several
@ -1396,10 +1391,10 @@ class API():
"""
return self.part
def convert_date(self, stamp):
def DateToKodi(self, stamp):
"""
convert_date(stamp) converts a Unix time stamp (seconds passed since
January 1 1970) to a propper, human-readable time stamp
converts a Unix time stamp (seconds passed sinceJanuary 1 1970) to a
propper, human-readable time stamp used by Kodi
"""
# DATEFORMAT = xbmc.getRegion('dateshort')
# TIMEFORMAT = xbmc.getRegion('meridiem')
@ -1415,85 +1410,53 @@ class API():
# else:
# localtime = time.strftime('%H:%M', date_time)
# return localtime + ' ' + localdate
DATEFORMAT = xbmc.getRegion('dateshort')
TIMEFORMAT = xbmc.getRegion('meridiem')
date_time = time.localtime(float(stamp))
localdate = time.strftime('%Y-%m-%dT%H:%M:%SZ', date_time)
try:
DATEFORMAT = xbmc.getRegion('dateshort')
TIMEFORMAT = xbmc.getRegion('meridiem')
date_time = time.localtime(float(stamp))
localdate = time.strftime('%Y-%m-%dT%H:%M:%SZ', date_time)
except:
localdate = None
return localdate
def getType(self):
"""
Returns the type of media, e.g. 'movie' or 'clip' for trailers
"""
# XML
try:
item = self.item.attrib
# JSON
except AttributeError:
item = self.item
return item.get('type', '')
return self.item.attrib.get('type', None)
def getChecksum(self):
"""
Can be used on both XML and JSON
Returns a string, not int
"""
item = self.item
# XML
try:
item = item[0].attrib
# JSON
except (AttributeError, KeyError):
pass
# Include a letter to prohibit saving as an int!
checksum = "K%s%s" % (self.getRatingKey(),
item.get('updatedAt', ''))
self.item.attrib.get('updatedAt', ''))
return checksum
def getRatingKey(self):
"""
Can be used on both XML and JSON
Returns the Plex key such as '246922' as a string
"""
# XML
try:
result = self.item.attrib
# JSON
except AttributeError:
item = self.item
return item['ratingKey']
return self.item.attrib.get('ratingKey', '')
def getKey(self):
"""
Can be used on both XML and JSON
Returns the Plex key such as '/library/metadata/246922'
"""
item = self.item
# XML
try:
item = item[0].attrib
# JSON
except (AttributeError, KeyError):
pass
key = item['key']
return str(key)
return self.item.attrib.get('key', None)
def getIndex(self):
"""
Returns the 'index' of an PMS XML reply. Depicts e.g. season number.
"""
item = self.item[0].attrib
index = item['index']
return str(index)
return self.item.attrib.get('index', None)
def getDateCreated(self):
"""
Returns the date when this library item was created
"""
item = self.item[0].attrib
dateadded = item['addedAt']
dateadded = self.convert_date(dateadded)
return dateadded
return self.DateToKodi(self.item.attrib.get('addedAt', None))
def getUserData(self):
"""
@ -1508,7 +1471,7 @@ class API():
'Rating': rating
}
"""
item = self.item
item = self.item.attrib
# Default
favorite = False
playcount = None
@ -1517,13 +1480,6 @@ class API():
resume = 0
rating = 0
# XML
try:
item = item[0].attrib
# JSON
except (AttributeError, KeyError):
pass
try:
playcount = int(item['viewCount'])
except KeyError:
@ -1533,8 +1489,7 @@ class API():
played = True
try:
lastPlayedDate = int(item['lastViewedAt'])
lastPlayedDate = self.convert_date(lastPlayedDate)
lastPlayedDate = self.DateToKodi(int(item['lastViewedAt']))
except KeyError:
lastPlayedDate = None
@ -1559,12 +1514,11 @@ class API():
'Producer': list
}
"""
item = self.item
director = []
writer = []
cast = []
producer = []
for child in item[0]:
for child in self.item:
if child.tag == 'Director':
director.append(child.attrib['tag'])
elif child.tag == 'Writer':
@ -1591,7 +1545,6 @@ class API():
('Role': xxx for cast/actors only, None if not found)
}
"""
item = self.item
people = []
# Key of library: Plex-identifier. Value represents the Kodi/emby side
people_of_interest = {
@ -1600,7 +1553,7 @@ class API():
'Role': 'Actor',
'Producer': 'Producer'
}
for child in item[0]:
for child in self.item:
if child.tag in people_of_interest.keys():
name = child.attrib['tag']
name_id = child.attrib['id']
@ -1630,9 +1583,8 @@ class API():
"""
Returns a list of genres found. (Not a string)
"""
item = self.item
genre = []
for child in item[0]:
for child in self.item:
if child.tag == 'Genre':
genre.append(child.attrib['tag'])
return genre
@ -1643,8 +1595,7 @@ class API():
Return IMDB, e.g. "imdb://tt0903624?lang=en". Returns None if not found
"""
item = self.item
item = item[0].attrib
item = self.item.attrib
try:
item = item['guid']
except KeyError:
@ -1660,99 +1611,50 @@ class API():
def getTitle(self):
"""
Returns an item's name/title or "Missing Title Name" for both XML and
JSON PMS replies
Returns an item's name/title or "Missing Title Name".
Output:
title, sorttitle
sorttitle = title, if no sorttitle is found
"""
item = self.item
# XML
try:
item = item[0].attrib
# JSON
except (AttributeError, KeyError):
pass
try:
title = item['title']
except:
title = 'Missing Title Name'
try:
sorttitle = item['titleSort']
except KeyError:
sorttitle = title
title = self.item.attrib.get('title', 'Missing Title Name')
sorttitle = self.item.attrib.get('titleSort', title)
return title, sorttitle
def getPlot(self):
"""
Returns the plot or None.
"""
item = self.item
item = item[0].attrib
try:
plot = item['summary']
except:
plot = None
return plot
return self.item.attrib.get('summary', None)
def getTagline(self):
"""
Returns a shorter tagline or None
"""
item = self.item
item = item[0].attrib
try:
tagline = item['tagline']
except KeyError:
tagline = None
return tagline
return self.item.attrib.get('tagline', None)
def getAudienceRating(self):
"""
Returns the audience rating or None
"""
item = self.item
item = item[0].attrib
try:
rating = item['audienceRating']
except KeyError:
rating = None
return rating
return self.item.attrib.get('audienceRating', None)
def getYear(self):
"""
Returns the production(?) year ("year") or None
"""
item = self.item
item = item[0].attrib
try:
year = item['year']
except KeyError:
year = None
return year
return self.item.attrib.get('year', None)
def getRuntime(self):
"""
Resume point of time and runtime/totaltime in seconds, rounded to 6th
decimal.
Resume point of time and runtime/totaltime in rounded to seconds.
Time from Plex server is measured in milliseconds.
Kodi: seconds
Output:
resume, runtime as floats. 0.0 if not found
resume, runtime as ints. 0 if not found
"""
time_factor = PlexToKodiTimefactor()
# XML
try:
item = self.item[0].attrib
# JSON
except (AttributeError, KeyError):
pass
item = self.item.attrib
try:
runtime = float(item['duration'])
@ -1763,30 +1665,16 @@ class API():
except KeyError:
resume = 0.0
# Adjust the resume point by x seconds as chosen by the user in the
# settings
if resume:
# To avoid negative bookmark
if resume > self.jumpback:
resume = resume - self.jumpback
runtime = runtime * time_factor
resume = resume * time_factor
resume = round(resume, 6)
runtime = round(runtime, 6)
runtime = int(runtime * PlexToKodiTimefactor())
resume = int(resume * PlexToKodiTimefactor())
return resume, runtime
def getMpaa(self):
"""
Get the content rating or None
"""
mpaa = self.item.attrib.get('contentRating', None)
# Convert more complex cases
item = self.item
item = item[0].attrib
try:
mpaa = item['contentRating']
except KeyError:
mpaa = None
if mpaa in ("NR", "UR"):
# Kodi seems to not like NR, but will accept Rated Not Rated
mpaa = "Rated Not Rated"
@ -1796,9 +1684,8 @@ class API():
"""
Returns a list of all countries found in item.
"""
item = self.item
country = []
for child in item[0]:
for child in self.item:
if child.tag == 'Country':
country.append(child.attrib['tag'])
return country
@ -1807,23 +1694,15 @@ class API():
"""
Returns the "originallyAvailableAt" or None
"""
item = self.item
item = item[0].attrib
try:
premiere = item['originallyAvailableAt']
except:
premiere = None
return premiere
return self.item.attrib.get('originallyAvailableAt', None)
def getStudios(self):
"""
Returns a list with a single entry for the studio, or an empty list
"""
item = self.item
studio = []
item = item[0].attrib
try:
studio.append(self.getStudio(item['studio']))
studio.append(self.getStudio(self.item.attrib['studio']))
except KeyError:
pass
return studio
@ -1862,7 +1741,7 @@ class API():
Episode number, Plex: 'index'
]
"""
item = self.item[0].attrib
item = self.item.attrib
key = item['grandparentRatingKey']
title = item['grandparentTitle']
season = item['parentIndex']
@ -1891,13 +1770,7 @@ class API():
If not found, empty str is returned
"""
# XML:
try:
item = self.item.attrib
# JSON
except AttributeError:
item = self.item
return item.get('playQueueItemID', '')
return self.item.atrrib.get('playQueueItemID', '')
def getDataFromPartOrMedia(self, key):
"""
@ -1906,14 +1779,8 @@ class API():
If all fails, None is returned.
"""
# JSON
try:
media = self.item['_children'][0]
part = media['_children'][self.part]
# XML
except TypeError:
media = self.item[0].attrib
part = self.item[0][self.part].attrib
media = self.item.attrib
part = self.item[self.part].attrib
try:
try:
@ -1979,26 +1846,25 @@ class API():
'originallyAvailableAt':
'year':
"""
extras = self.item[0].find('Extras')
elements = []
if not extras:
return elements
for extra in extras:
for extra in self.item.find('Extras'):
# Trailer:
key = extra.attrib['key']
title = extra.attrib['title']
thumb = extra.attrib['thumb']
duration = extra.attrib['duration']
year = extra.attrib['year']
extraType = extra.attrib['extraType']
originallyAvailableAt = extra.attrib['originallyAvailableAt']
elements.append({'key': key,
'title': title,
'thumb': thumb,
'duration': duration,
'extraType': extraType,
'originallyAvailableAt': originallyAvailableAt,
'year': year})
key = extra.attrib.get('key', None)
title = extra.attrib.get('title', None)
thumb = extra.attrib.get('thumb', None)
duration = float(extra.attrib.get('duration', 0.0))
year = extra.attrib.get('year', None)
extraType = extra.attrib.get('extraType', None)
originallyAvailableAt = extra.attrib.get(
'originallyAvailableAt', None)
elements.append(
{'key': key,
'title': title,
'thumb': thumb,
'duration': int(duration * PlexToKodiTimefactor()),
'extraType': extraType,
'originallyAvailableAt': originallyAvailableAt,
'year': year})
return elements
def getMediaStreams(self):
@ -2014,24 +1880,20 @@ class API():
'subtitle': list of subtitle languages (or "Unknown")
}
"""
item = self.item
videotracks = []
audiotracks = []
subtitlelanguages = []
aspectratio = None
try:
aspectratio = item[0][0].attrib['aspectRatio']
except KeyError:
pass
# Sometimes, aspectratio is on the "toplevel"
aspectratio = self.item[0].attrib.get('aspectRatio', None)
# TODO: what if several Media tags exist?!?
# Loop over parts
for child in item[0][0]:
container = child.attrib['container'].lower()
for child in self.item[0]:
container = child.attrib.get('container', None)
# Loop over Streams
for grandchild in child:
mediaStream = grandchild.attrib
type = int(mediaStream['streamType'])
if type == 1: # Video streams
mediaType = int(mediaStream.get('streamType', 999))
if mediaType == 1: # Video streams
videotrack = {}
videotrack['codec'] = mediaStream['codec'].lower()
if "msmpeg4" in videotrack['codec']:
@ -2043,21 +1905,17 @@ class API():
elif "h264" in videotrack['codec']:
if container in ("mp4", "mov", "m4v"):
videotrack['codec'] = "avc1"
videotrack['height'] = mediaStream.get('height')
videotrack['width'] = mediaStream.get('width')
videotrack['height'] = mediaStream.get('height', None)
videotrack['width'] = mediaStream.get('width', None)
# TODO: 3d Movies?!?
# videotrack['Video3DFormat'] = item.get('Video3DFormat')
try:
aspectratio = mediaStream['aspectRatio']
except KeyError:
if not aspectratio:
aspectratio = round(float(videotrack['width'] / videotrack['height']), 6)
aspectratio = mediaStream.get('aspectRatio', aspectratio)
videotrack['aspect'] = aspectratio
# TODO: Video 3d format
videotrack['video3DFormat'] = None
videotracks.append(videotrack)
elif type == 2: # Audio streams
elif mediaType == 2: # Audio streams
audiotrack = {}
audiotrack['codec'] = mediaStream['codec'].lower()
profile = mediaStream['codecID'].lower()
@ -2070,17 +1928,16 @@ class API():
audiotrack['language'] = 'unknown'
audiotracks.append(audiotrack)
elif type == 3: # Subtitle streams
elif mediaType == 3: # Subtitle streams
try:
subtitlelanguages.append(mediaStream['language'])
except:
subtitlelanguages.append("Unknown")
media = {
return {
'video': videotracks,
'audio': audiotracks,
'subtitle': subtitlelanguages
}
return media
def getAllArtwork(self, parentInfo=False):
"""
@ -2097,15 +1954,7 @@ class API():
'Backdrop': [] Plex key: "art". Only 1 pix
}
"""
server = self.server
item = self.item
# XML
try:
item = item[0].attrib
# JSON
except (AttributeError, KeyError):
pass
item = self.item.attrib
maxHeight = 10000
maxWidth = 10000
@ -2130,7 +1979,7 @@ class API():
# Get background artwork URL
try:
background = item['art']
background = "%s%s" % (server, background)
background = "%s%s" % (self.server, background)
background = self.addPlexCredentialsToUrl(background)
except KeyError:
background = ""
@ -2138,7 +1987,7 @@ class API():
# Get primary "thumb" pictures:
try:
primary = item['thumb']
primary = "%s%s" % (server, primary)
primary = "%s%s" % (self.server, primary)
primary = self.addPlexCredentialsToUrl(primary)
except KeyError:
primary = ""
@ -2160,7 +2009,7 @@ class API():
artwork = (
"%s/emby/Items/%s/Images/Backdrop/%s?"
"MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s"
% (server, parentId, backdropIndex,
% (self.server, parentId, backdropIndex,
maxWidth, maxHeight, parentbackdroptag, customquery))
allartworks['Backdrop'].append(artwork)
backdropIndex += 1
@ -2178,7 +2027,7 @@ class API():
artwork = (
"%s/emby/Items/%s/Images/%s/0?"
"MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s"
% (server, parentId, parentart,
% (self.server, parentId, parentart,
maxWidth, maxHeight, parentTag, customquery))
allartworks[parentart] = artwork
@ -2192,11 +2041,12 @@ class API():
artwork = (
"%s/emby/Items/%s/Images/Primary/0?"
"MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s"
% (server, parentId, maxWidth, maxHeight, parentTag, customquery))
% (self.server, parentId, maxWidth, maxHeight, parentTag, customquery))
allartworks['Primary'] = artwork
return allartworks
def getTranscodeVideoPath(self, action, quality={}, subtitle={}, audioboost=None, options={}):
def getTranscodeVideoPath(self, action, quality={}, subtitle={},
audioboost=None, options={}):
"""
Transcode Video support; returns the URL to get a media started
@ -2329,12 +2179,12 @@ class API():
mapping = {}
item = self.item
itemid = self.getRatingKey()
try:
mediastreams = item[0][0][0]
mediastreams = item[0][self.part]
except (TypeError, KeyError, IndexError):
return
itemid = self.getRatingKey()
kodiindex = 0
for stream in mediastreams:
# index = stream['Index']
@ -2394,9 +2244,3 @@ class API():
if not xml:
self.logMsg("Error retrieving metadata for %s" % url, 1)
return xml
def GetParts(self):
"""
Returns the parts of the specified video child in the XML response
"""
return self.item[0][0]

View file

@ -115,16 +115,15 @@ def GetPlayQueue(playQueueID):
return xml
def GetPlexMetadata(key, JSON=True):
def GetPlexMetadata(key):
"""
Returns raw API metadata for key as an etree XML.
Can be called with either Plex key '/library/metadata/xxxx'metadata
OR with the digits 'xxxx' only.
Returns an empty string '' if something went wrong
Returns None if something went wrong
"""
xml = ''
key = str(key)
if '/library/metadata/' in key:
url = "{server}" + key
@ -133,82 +132,72 @@ def GetPlexMetadata(key, JSON=True):
arguments = {
'checkFiles': 1, # No idea
'includeExtras': 1, # Trailers and Extras => Extras
'includeRelated': 1, # Similar movies => Video -> Related
'includeRelatedCount': 5,
'includeOnDeck': 1,
# 'includeRelated': 1, # Similar movies => Video -> Related
# 'includeRelatedCount': 5,
# 'includeOnDeck': 1,
'includeChapters': 1,
'includePopularLeaves': 1,
'includeConcerts': 1
}
url = url + '?' + urlencode(arguments)
if not JSON:
headerOptions = {'Accept': 'application/xml'}
else:
headerOptions = {}
xml = downloadutils.DownloadUtils().downloadUrl(url, headerOptions=headerOptions)
xml = downloadutils.DownloadUtils().downloadUrl(url)
# Did we receive a valid XML?
try:
xml.tag
xml.attrib
# Nope we did not receive a valid XML
except AttributeError:
logMsg(title, "Error retrieving metadata for %s" % url, -1)
xml = ''
xml = None
return xml
def GetAllPlexChildren(key):
"""
Returns a list (raw JSON API dump) of all Plex children for the key.
Returns a list (raw xml API dump) of all Plex children for the key.
(e.g. /library/metadata/194853/children pointing to a season)
Input:
key Key to a Plex item, e.g. 12345
"""
result = []
url = "{server}/library/metadata/%s/children" % key
jsondata = downloadutils.DownloadUtils().downloadUrl(url)
xml = downloadutils.DownloadUtils().downloadUrl(
"{server}/library/metadata/%s/children" % key)
try:
result = jsondata['_children']
except KeyError:
xml.attrib
except AttributeError:
logMsg(
title, "Error retrieving all children for Plex item %s" % key, -1)
pass
return result
xml = None
return xml
def GetPlexSectionResults(viewId, headerOptions={}):
"""
Returns a list (raw JSON or XML API dump) of all Plex items in the Plex
Returns a list (XML API dump) of all Plex items in the Plex
section with key = viewId.
Returns None if something went wrong
"""
result = []
url = "{server}/library/sections/%s/all" % viewId
jsondata = downloadutils.DownloadUtils().downloadUrl(url, headerOptions=headerOptions)
result = downloadutils.DownloadUtils().downloadUrl(
url, headerOptions=headerOptions)
try:
result = jsondata['_children']
except TypeError:
# Maybe we received an XML, check for that with tag attribute
try:
jsondata.tag
result = jsondata
# Nope, not an XML, abort
except AttributeError:
logMsg(title,
"Error retrieving all items for Plex section %s"
% viewId, -1)
return result
except KeyError:
result.tag
# Nope, not an XML, abort
except AttributeError:
logMsg(title,
"Error retrieving all items for Plex section %s"
% viewId, -1)
result = None
return result
def GetAllPlexLeaves(viewId, lastViewedAt=None, updatedAt=None,
headerOptions={}):
"""
Returns a list (raw JSON or XML API dump) of all Plex subitems for the
key.
Returns a list (raw XML API dump) of all Plex subitems for the key.
(e.g. /library/sections/2/allLeaves pointing to all TV shows)
Input:
@ -226,7 +215,6 @@ def GetAllPlexLeaves(viewId, lastViewedAt=None, updatedAt=None,
Relevant "master time": PMS server. I guess this COULD lead to problems,
e.g. when server and client are in different time zones.
"""
result = []
args = []
url = "{server}/library/sections/%s/allLeaves?" % viewId
if lastViewedAt:
@ -234,24 +222,18 @@ def GetAllPlexLeaves(viewId, lastViewedAt=None, updatedAt=None,
if updatedAt:
args.append('updatedAt>=%s' % updatedAt)
args = '&'.join(args)
jsondata = downloadutils.DownloadUtils().downloadUrl(
xml = downloadutils.DownloadUtils().downloadUrl(
url+args, headerOptions=headerOptions)
try:
result = jsondata['_children']
except TypeError:
# Maybe we received an XML, check for that with tag attribute
try:
jsondata.tag
result = jsondata
# Nope, not an XML, abort
except AttributeError:
logMsg(title,
"Error retrieving all leaves for Plex section %s"
% viewId, -1)
return result
except KeyError:
logMsg("Error retrieving all leaves for Plex viewId %s" % viewId, -1)
return result
xml.attrib
# Nope, not an XML, abort
except AttributeError:
logMsg(title,
"Error retrieving all leaves for Plex section %s"
% viewId, -1)
xml = None
return xml
def GetPlexCollections(mediatype):

View file

@ -180,9 +180,9 @@ class DownloadUtils():
plx = PlexAPI.PlexAPI()
if authenticate:
options['X-Plex-Token'] = self.token
header = plx.getXArgsDeviceInfo(options=options, JSON=True)
header = plx.getXArgsDeviceInfo(options=options)
else:
header = plx.getXArgsDeviceInfo(options=options, JSON=True)
header = plx.getXArgsDeviceInfo(options=options)
return header
def downloadUrl(self, url, postBody=None, type="GET", parameters=None, authenticate=True, headerOptions={}):
@ -309,18 +309,19 @@ class DownloadUtils():
elif r.status_code == requests.codes.ok:
try:
# UNICODE - JSON object
r = r.json()
# Allow for xml responses
r = etree.fromstring(r.content)
self.logMsg("====== 200 Success ======", 2)
self.logMsg("Response: %s" % r, 2)
self.logMsg("Received an XML response for: %s" % url, 2)
return r
except:
# Allow for xml responses
try:
r = etree.fromstring(r.content)
# UNICODE - JSON object
r = r.json()
self.logMsg("====== 200 Success ======", 2)
self.logMsg("Received an XML response for: %s" % url, 2)
self.logMsg("Response: %s" % r, 2)
return r
except:
try:

View file

@ -105,7 +105,7 @@ def PassPlaylist(xml, resume=0):
def doPlayback(itemid, dbid):
utils.logMsg(title, "doPlayback called with %s %s"
% (itemid, dbid), 1)
item = PlexFunctions.GetPlexMetadata(itemid, JSON=True)
item = PlexFunctions.GetPlexMetadata(itemid)
playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
# If current playlist is NOT empty, we only need to update the item url
if playlist.size() != 0:

View file

@ -317,12 +317,15 @@ class Movies(Items):
userdata = API.getUserData()
playcount = userdata['PlayCount']
dateplayed = userdata['LastPlayedDate']
resume = userdata['Resume']
runtime = userdata['Runtime']
# item details
people = API.getPeople()
writer = API.joinList(people['Writer'])
director = API.joinList(people['Director'])
genres = API.getGenres()
genre = API.joinList(genres)
title, sorttitle = API.getTitle()
plot = API.getPlot()
shortplot = None
@ -331,10 +334,8 @@ class Movies(Items):
rating = API.getAudienceRating()
year = API.getYear()
imdb = API.getProvider('Imdb')
resume, runtime = API.getRuntime()
imdb = API.getProvider()
mpaa = API.getMpaa()
genre = API.joinList(genres)
countries = API.getCountry()
country = API.joinList(countries)
studios = API.getStudios()
@ -350,8 +351,8 @@ class Movies(Items):
for extra in extras:
# Only get 1st trailer element
if extra['extraType'] == '1':
trailer = extra['key']
trailer = "plugin://plugin.video.plexkodiconnect/trailer/?id=%s&mode=play" % trailer
trailer = ("plugin://plugin.video.plexkodiconnect/trailer/?"
"id=%s&mode=play") % extra['key']
self.logMsg("Trailer for %s: %s" % (itemid, trailer), 2)
break

View file

@ -63,10 +63,8 @@ class ThreadedGetMetadata(threading.Thread):
continue
# Download Metadata
plexXML = PlexFunctions.GetPlexMetadata(updateItem['itemId'])
try:
plexXML.tag
except:
# Did not receive a valid XML - skip that one for now
if not plexXML:
# Did not receive a valid XML - skip that item for now
queue.task_done()
continue
@ -129,9 +127,11 @@ class ThreadedProcessMetadata(threading.Thread):
title = updateItem['title']
itemSubFkt = getattr(item, method)
with lock:
itemSubFkt(plexitem,
viewtag=viewName,
viewid=viewId)
# Get the one child entry in the xml and process
for child in plexitem:
itemSubFkt(child,
viewtag=viewName,
viewid=viewId)
# Keep track of where we are at
processMetadataCount += 1
processingViewName = title
@ -303,7 +303,7 @@ class LibrarySync(threading.Thread):
if not items:
continue
# Get one itemtype, because they're the same in the PMS section
plexType = items[0]['type']
plexType = items[0].attrib['type']
# Populate self.updatelist
self.GetUpdatelist(items,
PlexFunctions.GetItemClassFromType(plexType),
@ -456,7 +456,10 @@ class LibrarySync(threading.Thread):
vnodes = self.vnodes
# Get views
result = doUtils.downloadUrl("{server}/library/sections")['_children']
result = doUtils.downloadUrl("{server}/library/sections")
if not result:
self.logMsg("Error download PMS views, abort maintainViews", -1)
return False
# total nodes for window properties
vnodes.clearProperties()
@ -467,7 +470,8 @@ class LibrarySync(threading.Thread):
'movie',
'show'
]
for folder in result:
for folderItem in result:
folder = folderItem.attrib
mediatype = folder['type']
if mediatype in mediatypes:
folderid = folder['key']
@ -567,13 +571,12 @@ class LibrarySync(threading.Thread):
embyconn.close()
kodiconn.close()
def GetUpdatelist(self, elementList, itemType, method, viewName, viewId):
def GetUpdatelist(self, xml, itemType, method, viewName, viewId):
"""
Adds items to self.updatelist as well as self.allPlexElementsId dict
Input:
elementList: List of elements, e.g. list of '_children'
movie elements as received from PMS
xml: PMS answer for section items
itemType: 'Movies', 'TVShows', ...
method: Method name to be called with this itemtype
see itemtypes.py
@ -596,12 +599,10 @@ class LibrarySync(threading.Thread):
"""
if self.compare:
# Manual sync
for item in elementList:
# Skipping XML item 'title=All episodes' without a 'ratingKey'
if not item.get('ratingKey', False):
for item in xml:
# Skipping items 'title=All episodes' without a 'ratingKey'
if not item.attrib.get('ratingKey', False):
continue
if self.threadStopped():
return False
API = PlexAPI.API(item)
plex_checksum = API.getChecksum()
itemId = API.getRatingKey()
@ -619,12 +620,10 @@ class LibrarySync(threading.Thread):
'title': title})
else:
# Initial or repair sync: get all Plex movies
for item in elementList:
for item in xml:
# Only look at valid items = Plex library items
if not item.get('ratingKey', False):
if not item.attrib.get('ratingKey', False):
continue
if self.threadStopped():
return False
API = PlexAPI.API(item)
itemId = API.getRatingKey()
title, sorttitle = API.getTitle()
@ -679,7 +678,7 @@ class LibrarySync(threading.Thread):
thread.setDaemon(True)
thread.start()
threads.append(thread)
self.logMsg("Download threads spawned", 1)
self.logMsg("%s download threads spawned" % len(threads), 1)
# Spawn one more thread to process Metadata, once downloaded
thread = ThreadedProcessMetadata(processMetadataQueue,
itemType,
@ -758,6 +757,9 @@ class LibrarySync(threading.Thread):
viewId = view['id']
viewName = view['name']
all_plexmovies = PlexFunctions.GetPlexSectionResults(viewId)
if not all_plexmovies:
self.logMsg("Couldnt get section items, aborting for view.", 1)
continue
# Populate self.updatelist and self.allPlexElementsId
self.GetUpdatelist(all_plexmovies,
itemType,
@ -768,6 +770,8 @@ class LibrarySync(threading.Thread):
self.logMsg("Processed view %s with ID %s" % (viewName, viewId), 1)
# Update viewstate
for view in views:
if self.threadStopped():
return False
self.PlexUpdateWatched(view['id'], itemType)
##### PROCESS DELETES #####
@ -892,6 +896,10 @@ class LibrarySync(threading.Thread):
viewId = view['id']
viewName = view['name']
allPlexTvShows = PlexFunctions.GetPlexSectionResults(viewId)
if not allPlexTvShows:
self.logMsg(
"Error downloading show view xml for view %s" % viewId, -1)
continue
# Populate self.updatelist and self.allPlexElementsId
self.GetUpdatelist(allPlexTvShows,
itemType,
@ -910,6 +918,10 @@ class LibrarySync(threading.Thread):
return False
# Grab all seasons to tvshow from PMS
seasons = PlexFunctions.GetAllPlexChildren(tvShowId)
if not seasons:
self.logMsg(
"Error downloading season xml for show %s" % tvShowId, -1)
continue
# Populate self.updatelist and self.allPlexElementsId
self.GetUpdatelist(seasons,
itemType,
@ -926,6 +938,11 @@ class LibrarySync(threading.Thread):
return False
# Grab all episodes to tvshow from PMS
episodes = PlexFunctions.GetAllPlexLeaves(view['id'])
if not episodes:
self.logMsg(
"Error downloading episod xml for view %s"
% view.get('name'), -1)
continue
# Populate self.updatelist and self.allPlexElementsId
self.GetUpdatelist(episodes,
itemType,