Switched metadata processing from JSON to XML

This commit is contained in:
tomkat83 2015-12-31 10:53:22 +01:00
parent f2294569e6
commit 3fe10ba851
4 changed files with 210 additions and 91 deletions

View file

@ -612,10 +612,10 @@ class PlexAPI():
xargs['X-Plex-Product'] = self.addonName xargs['X-Plex-Product'] = self.addonName
xargs['X-Plex-Version'] = self.plexversion xargs['X-Plex-Version'] = self.plexversion
xargs['X-Plex-Client-Identifier'] = self.clientId xargs['X-Plex-Client-Identifier'] = self.clientId
if options:
xargs.update(options)
if JSON: if JSON:
xargs['Accept'] = 'application/json' xargs['Accept'] = 'application/json'
if options:
xargs.update(options)
return xargs return xargs
def getXMLFromMultiplePMS(self, ATV_udid, path, type, options={}): def getXMLFromMultiplePMS(self, ATV_udid, path, type, options={}):
@ -1293,19 +1293,28 @@ class PlexAPI():
Can be called with either Plex key '/library/metadata/xxxx'metadata Can be called with either Plex key '/library/metadata/xxxx'metadata
OR with the digits 'xxxx' only. OR with the digits 'xxxx' only.
""" """
result = [] xml = ''
key = str(key) key = str(key)
if '/library/metadata/' in key: if '/library/metadata/' in key:
url = "{server}" + key url = "{server}" + key
else: else:
url = "{server}/library/metadata/" + key url = "{server}/library/metadata/" + key
jsondata = self.doUtils.downloadUrl(url) arguments = {
try: 'checkFiles': 1, # No idea
result = jsondata['_children'][0] 'includeExtras': 1, # Trailers and Extras => Extras
except KeyError: 'includeRelated': 1, # Similar movies => Video -> Related
'includeRelatedCount': 5,
'includeOnDeck': 1,
'includeChapters': 1,
'includePopularLeaves': 1,
'includeConcerts': 1
}
url = url + '?' + urllib.urlencode(arguments)
headerOptions = {'Accept': 'application/xml'}
xml = self.doUtils.downloadUrl(url, headerOptions=headerOptions)
if not xml:
self.logMsg("Error retrieving metadata for %s" % url, 1) self.logMsg("Error retrieving metadata for %s" % url, 1)
pass return xml
return result
class API(): class API():
@ -1345,7 +1354,7 @@ class API():
# return localtime + ' ' + localdate # return localtime + ' ' + localdate
DATEFORMAT = xbmc.getRegion('dateshort') DATEFORMAT = xbmc.getRegion('dateshort')
TIMEFORMAT = xbmc.getRegion('meridiem') TIMEFORMAT = xbmc.getRegion('meridiem')
date_time = time.localtime(stamp) date_time = time.localtime(float(stamp))
localdate = time.strftime('%Y-%m-%d', date_time) localdate = time.strftime('%Y-%m-%d', date_time)
return localdate return localdate
@ -1356,6 +1365,12 @@ class API():
""" """
item = self.item item = self.item
# Include a letter to prohibit saving as an int! # Include a letter to prohibit saving as an int!
# xml
try:
item = item[0].attrib
# json
except KeyError:
pass
checksum = "K%s%s%s%s%s" % ( checksum = "K%s%s%s%s%s" % (
self.getKey(), self.getKey(),
item['updatedAt'], item['updatedAt'],
@ -1371,11 +1386,24 @@ class API():
""" """
item = self.item item = self.item
key_regex = re.compile(r'/(\d+)$') key_regex = re.compile(r'/(\d+)$')
key = key_regex.findall(item['key'])[0] # xml
try:
item = item[0].attrib
# json
except KeyError:
pass
key = item['key']
key = key_regex.findall(key)[0]
return str(key) return str(key)
def getDateCreated(self): def getDateCreated(self):
item = self.item item = self.item
# xml
try:
item = item[0].attrib
# json
except KeyError:
pass
try: try:
dateadded = item['addedAt'] dateadded = item['addedAt']
dateadded = self.convert_date(dateadded) dateadded = self.convert_date(dateadded)
@ -1393,6 +1421,12 @@ class API():
resume = 0 resume = 0
rating = 0 rating = 0
# xml
try:
item = item[0].attrib
# json
except KeyError:
pass
try: try:
playcount = int(item['viewCount']) playcount = int(item['viewCount'])
except KeyError: except KeyError:
@ -1423,7 +1457,8 @@ class API():
def getPeople(self): def getPeople(self):
""" """
returns a dictionary of lists of people found in item. Input is Plex' XMl
Returns a dictionary of lists of people found in item.
{ {
'Director': list, 'Director': list,
@ -1433,21 +1468,19 @@ class API():
} }
""" """
item = self.item item = self.item
item = item['_children']
# Process People
director = [] director = []
writer = [] writer = []
cast = [] cast = []
producer = [] producer = []
for entry in item: for child in item[0]:
if entry['_elementType'] == 'Director': if child.tag == 'Director':
director.append(entry['tag']) director.append(child.attrib['tag'])
elif entry['_elementType'] == 'Writer': elif child.tag == 'Writer':
writer.append(entry['tag']) writer.append(child.attrib['tag'])
elif entry['_elementType'] == 'Role': elif child.tag == 'Role':
cast.append(entry['tag']) cast.append(child.attrib['tag'])
elif entry['_elementType'] == 'Producer': elif child.tag == 'Producer':
producer.append(entry['tag']) producer.append(child.attrib['tag'])
return { return {
'Director': director, 'Director': director,
'Writer': writer, 'Writer': writer,
@ -1462,10 +1495,11 @@ class API():
'Name': xxx, 'Name': xxx,
'Type': xxx, 'Type': xxx,
'Id': xxx 'Id': xxx
'imageurl': url to picture
('Role': xxx for cast/actors only) ('Role': xxx for cast/actors only)
} }
""" """
item = self.item['_children'] item = self.item
people = [] people = []
# Key of library: Plex-identifier. Value represents the Kodi/emby side # Key of library: Plex-identifier. Value represents the Kodi/emby side
people_of_interest = { people_of_interest = {
@ -1474,26 +1508,30 @@ class API():
'Role': 'Actor', 'Role': 'Actor',
'Producer': 'Producer' 'Producer': 'Producer'
} }
for entry in item: for child in item[0]:
if entry['_elementType'] in people_of_interest.keys(): if child.tag in people_of_interest.keys():
name = entry['tag'] name = child.attrib['tag']
name_id = entry['id'] name_id = child.attrib['id']
Type = entry['_elementType'] Type = child.tag
Type = people_of_interest[Type] Type = people_of_interest[Type]
if Type == 'Actor': try:
Role = entry['role'] url = child.attrib['thumb']
people.append({ except KeyError:
'Name': name, url = None
'Type': Type, try:
'Id': name_id, Role = child.attrib['role']
'Role': Role except KeyError:
}) Role = None
else: people.append({
people.append({ 'Name': name,
'Name': name, 'Type': Type,
'Type': Type, 'Id': name_id,
'Id': name_id 'imageurl': url
}) })
if url:
people[-1].update({'imageurl': url})
if Role:
people[-1].update({'Role': Role})
return people return people
def getGenres(self): def getGenres(self):
@ -1501,11 +1539,10 @@ class API():
returns a list of genres found in item. (Not a string!!) returns a list of genres found in item. (Not a string!!)
""" """
item = self.item item = self.item
item = item['_children']
genre = [] genre = []
for entry in item: for child in item[0]:
if entry['_elementType'] == 'Genre': if child.tag == 'Genre':
genre.append(entry['tag']) genre.append(child.attrib['tag'])
return genre return genre
def getProvider(self, providername): def getProvider(self, providername):
@ -1518,6 +1555,12 @@ class API():
Return IMDB: "tt1234567" Return IMDB: "tt1234567"
""" """
item = self.item item = self.item
# xml
try:
item = item[0].attrib
# json
except KeyError:
pass
imdb_regex = re.compile(r'''( imdb_regex = re.compile(r'''(
imdb:// # imdb tag, which will be followed be tt1234567 imdb:// # imdb tag, which will be followed be tt1234567
(tt\d{7}) # actual IMDB ID, e.g. tt1234567 (tt\d{7}) # actual IMDB ID, e.g. tt1234567
@ -1540,8 +1583,14 @@ class API():
provider = None provider = None
return provider return provider
def GetTitle(self): def getTitle(self):
item = self.item item = self.item
# xml
try:
item = item[0].attrib
# json
except KeyError:
pass
title = item['title'] title = item['title']
try: try:
sorttitle = item['titleSort'] sorttitle = item['titleSort']
@ -1549,6 +1598,56 @@ class API():
sorttitle = title sorttitle = title
return title, sorttitle return title, sorttitle
def getPlot(self):
item = self.item
# xml
try:
item = item[0].attrib
# json
except KeyError:
pass
plot = item['summary']
return plot
def getTagline(self):
item = self.item
# xml
try:
item = item[0].attrib
# json
except KeyError:
pass
try:
tagline = item['tagline']
except KeyError:
tagline = None
return tagline
def getAudienceRating(self):
item = self.item
# xml
try:
item = item[0].attrib
# json
except KeyError:
pass
try:
rating = item['audienceRating']
except:
rating = None
return rating
def getYear(self):
item = self.item
# xml
try:
item = item[0].attrib
# json
except KeyError:
pass
year = item['year']
return year
def getRuntime(self): def getRuntime(self):
""" """
Resume point of time and runtime/totaltime. Rounded to 6th decimal. Resume point of time and runtime/totaltime. Rounded to 6th decimal.
@ -1557,10 +1656,16 @@ class API():
milliseconds on the Plex side and in seconds on the Kodi side. milliseconds on the Plex side and in seconds on the Kodi side.
""" """
item = self.item item = self.item
time_factor = 1/1000 # xml
runtime = item['duration'] * time_factor
try: try:
resume = item['viewOffset'] * time_factor item = item[0].attrib
# json
except KeyError:
pass
time_factor = 1/1000
runtime = int(item['duration']) * time_factor
try:
resume = int(item['viewOffset']) * time_factor
except KeyError: except KeyError:
resume = 0 resume = 0
resume = round(float(resume), 6) resume = round(float(resume), 6)
@ -1570,6 +1675,12 @@ class API():
def getMpaa(self): def getMpaa(self):
# Convert more complex cases # Convert more complex cases
item = self.item item = self.item
# xml
try:
item = item[0].attrib
# json
except KeyError:
pass
try: try:
mpaa = item['contentRating'] mpaa = item['contentRating']
except KeyError: except KeyError:
@ -1584,16 +1695,21 @@ class API():
Returns a list of all countries found in item. Returns a list of all countries found in item.
""" """
item = self.item item = self.item
item = item['_children']
country = [] country = []
for entry in item: for child in item[0]:
if entry['_elementType'] == 'Country': if child.tag == 'Country':
country.append(entry['tag']) country.append(child.attrib['tag'])
return country return country
def getStudios(self): def getStudios(self):
item = self.item item = self.item
studio = [] studio = []
# xml
try:
item = item[0].attrib
# json
except KeyError:
pass
try: try:
studio.append(self.getStudio(item['studio'])) studio.append(self.getStudio(item['studio']))
except KeyError: except KeyError:
@ -1621,9 +1737,13 @@ class API():
def getFilePath(self): def getFilePath(self):
item = self.item item = self.item
try:
item = item[0].attrib
# json
except KeyError:
pass
try: try:
filepath = item['key'] filepath = item['key']
except KeyError: except KeyError:
filepath = "" filepath = ""
@ -1656,28 +1776,23 @@ class API():
def getMediaStreams(self): def getMediaStreams(self):
item = self.item item = self.item
item = item['_children']
videotracks = [] videotracks = []
audiotracks = [] audiotracks = []
subtitlelanguages = [] subtitlelanguages = []
MediaStreams = []
aspectratio = None aspectratio = None
for entry in item: try:
if entry['_elementType'] == 'Media': aspectratio = item[0][0].attrib['aspectRatio']
MediaStreams.append(entry) except KeyError:
try: pass
aspectratio = entry['aspectRatio']
except KeyError:
pass
# Abort if no Media found
if not MediaStreams:
return
# Loop over parts: # Loop over parts:
# TODO: what if several Media tags exist?!? # TODO: what if several Media tags exist?!?
for part in MediaStreams[0]['_children']: # Loop over parts
for child in item[0][0]:
part = child.attrib
container = part['container'].lower() container = part['container'].lower()
for mediaStream in part['_children']: # Loop over Streams
for grandchild in child:
mediaStream = grandchild.attrib
try: try:
type = mediaStream['streamType'] type = mediaStream['streamType']
except KeyError: except KeyError:
@ -1737,8 +1852,6 @@ class API():
server = self.server server = self.server
item = self.item item = self.item
id = item['key']
maxHeight = 10000 maxHeight = 10000
maxWidth = 10000 maxWidth = 10000
customquery = "" customquery = ""
@ -1762,6 +1875,7 @@ class API():
# Process backdrops # Process backdrops
# Get background artwork URL # Get background artwork URL
item = item[0].attrib
try: try:
background = item['art'] background = item['art']
background = "%s%s" % (server, background) background = "%s%s" % (server, background)

View file

@ -13,6 +13,10 @@ import utils
import clientinfo import clientinfo
import PlexAPI import PlexAPI
try:
import xml.etree.cElementTree as etree
except ImportError:
import xml.etree.ElementTree as etree
################################################################################################## ##################################################################################################
@ -205,16 +209,16 @@ class DownloadUtils():
# Replace for the real values # Replace for the real values
url = url.replace("{server}", self.server) url = url.replace("{server}", self.server)
url = url.replace("{UserId}", self.userId) url = url.replace("{UserId}", self.userId)
header = self.getHeader(options=headerOptions)
# Prepare request # Prepare request
if type == "GET": if type == "GET":
r = s.get(url, json=postBody, params=parameters, timeout=timeout) r = s.get(url, json=postBody, params=parameters, timeout=timeout, headers=header)
elif type == "POST": elif type == "POST":
r = s.post(url, json=postBody, timeout=timeout) r = s.post(url, json=postBody, timeout=timeout, headers=header)
elif type == "DELETE": elif type == "DELETE":
r = s.delete(url, json=postBody, timeout=timeout) r = s.delete(url, json=postBody, timeout=timeout, headers=header)
elif type == "OPTIONS": elif type == "OPTIONS":
r = s.options(url, json=postBody, timeout=timeout) r = s.options(url, json=postBody, timeout=timeout, headers=header)
except AttributeError: except AttributeError:
# request session does not exists # request session does not exists
@ -317,12 +321,15 @@ class DownloadUtils():
return r return r
except: except:
# Allow for xml responses, but do not process them # Allow for xml responses
if 'xml' in r.headers.get('content-type'): try:
self.logMsg("Received an XML response for: %s" % url, 1) r = etree.fromstring(r.content)
return 'xml' self.logMsg("====== 200 Success ======", 2)
elif r.headers.get('content-type') != "text/html": self.logMsg("Received an XML response for: %s" % url, 2)
return r
except:
self.logMsg("Unable to convert the response for: %s" % url, 1) self.logMsg("Unable to convert the response for: %s" % url, 1)
self.logMsg("Content-type was: %s" % r.headers['content-type'], 1)
else: else:
r.raise_for_status() r.raise_for_status()

View file

@ -309,13 +309,13 @@ class Movies(Items):
writer = API.joinList(people['Writer']) writer = API.joinList(people['Writer'])
director = API.joinList(people['Director']) director = API.joinList(people['Director'])
genres = API.getGenres() genres = API.getGenres()
title, sorttitle = API.GetTitle() title, sorttitle = API.getTitle()
plot = item.get('summary', None) plot = API.getPlot()
shortplot = None shortplot = None
tagline = item.get('tagline', None) tagline = API.getTagline()
votecount = None votecount = None
rating = item.get('audienceRating', None) rating = API.getAudienceRating()
year = item.get('year', None) year = API.getYear()
imdb = API.getProvider('Imdb') imdb = API.getProvider('Imdb')
resume, runtime = API.getRuntime() resume, runtime = API.getRuntime()
mpaa = API.getMpaa() mpaa = API.getMpaa()
@ -438,8 +438,6 @@ class Movies(Items):
kodi_db.addCountries(movieid, countries, "movie") kodi_db.addCountries(movieid, countries, "movie")
# Process cast # Process cast
people = API.getPeopleList() people = API.getPeopleList()
# TODO: get IMDB pictures?
people = artwork.getPeopleArtwork(people)
kodi_db.addPeople(movieid, people, "movie") kodi_db.addPeople(movieid, people, "movie")
# Process genres # Process genres
kodi_db.addGenres(movieid, genres, "movie") kodi_db.addGenres(movieid, genres, "movie")

View file

@ -543,7 +543,7 @@ class LibrarySync(threading.Thread):
# Process individual movies # Process individual movies
if self.shouldStop(): if self.shouldStop():
return False return False
title = plexmovie['title'] title = plexmovie[0].attrib['title']
if pdialog: if pdialog:
percentage = int((float(count) / float(total))*100) percentage = int((float(count) / float(total))*100)
pdialog.update(percentage, message=title) pdialog.update(percentage, message=title)