Overhaul of fanart sync download
This commit is contained in:
parent
67668fdaac
commit
f2c7578a25
4 changed files with 98 additions and 103 deletions
|
@ -63,18 +63,57 @@ class Items(object):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
@CatchExceptions(warnuser=True)
|
@CatchExceptions(warnuser=True)
|
||||||
def getfanart(self, item, kodiId, mediaType, allartworks=None):
|
def getfanart(self, plex_id, refresh=False):
|
||||||
"""
|
"""
|
||||||
|
Tries to get additional fanart for movies (+sets) and TV shows.
|
||||||
|
|
||||||
|
Returns True if successful, False otherwise
|
||||||
"""
|
"""
|
||||||
API = PlexAPI.API(item)
|
with plexdb.Get_Plex_DB() as plex_db:
|
||||||
|
db_item = plex_db.getItem_byId(plex_id)
|
||||||
|
try:
|
||||||
|
kodi_id = db_item[0]
|
||||||
|
kodi_type = db_item[4]
|
||||||
|
except TypeError:
|
||||||
|
log.error('Could not get Kodi id for plex id %s, abort getfanart'
|
||||||
|
% plex_id)
|
||||||
|
return False
|
||||||
|
if refresh is True:
|
||||||
|
# Leave the Plex art untouched
|
||||||
|
allartworks = None
|
||||||
|
else:
|
||||||
|
with kodidb.GetKodiDB('video') as kodi_db:
|
||||||
|
allartworks = kodi_db.existingArt(kodi_id, kodi_type)
|
||||||
|
# Check if we even need to get additional art
|
||||||
|
needsupdate = False
|
||||||
|
for key, value in allartworks.iteritems():
|
||||||
|
if not value and not key == 'BoxRear':
|
||||||
|
needsupdate = True
|
||||||
|
break
|
||||||
|
if needsupdate is False:
|
||||||
|
log.debug('Already got all fanart for Plex id %s' % plex_id)
|
||||||
|
return True
|
||||||
|
|
||||||
|
xml = GetPlexMetadata(plex_id)
|
||||||
|
if xml is None:
|
||||||
|
# Did not receive a valid XML - skip that item for now
|
||||||
|
log.error("Could not get metadata for %s. Skipping that item "
|
||||||
|
"for now" % plex_id)
|
||||||
|
return False
|
||||||
|
elif xml == 401:
|
||||||
|
log.error('HTTP 401 returned by PMS. Too much strain? '
|
||||||
|
'Cancelling sync for now')
|
||||||
|
# Kill remaining items in queue (for main thread to cont.)
|
||||||
|
return False
|
||||||
|
API = PlexAPI.API(xml[0])
|
||||||
if allartworks is None:
|
if allartworks is None:
|
||||||
allartworks = API.getAllArtwork()
|
allartworks = API.getAllArtwork()
|
||||||
self.artwork.addArtwork(API.getFanartArtwork(allartworks),
|
self.artwork.addArtwork(API.getFanartArtwork(allartworks),
|
||||||
kodiId,
|
kodi_id,
|
||||||
mediaType,
|
kodi_type,
|
||||||
self.kodicursor)
|
self.kodicursor)
|
||||||
# Also get artwork for collections/movie sets
|
# Also get artwork for collections/movie sets
|
||||||
if mediaType == v.KODI_TYPE_MOVIE:
|
if kodi_type == v.KODI_TYPE_MOVIE:
|
||||||
for setname in API.getCollections():
|
for setname in API.getCollections():
|
||||||
log.debug('Getting artwork for movie set %s' % setname)
|
log.debug('Getting artwork for movie set %s' % setname)
|
||||||
setid = self.kodi_db.createBoxset(setname)
|
setid = self.kodi_db.createBoxset(setname)
|
||||||
|
@ -82,7 +121,8 @@ class Items(object):
|
||||||
setid,
|
setid,
|
||||||
v.KODI_TYPE_SET,
|
v.KODI_TYPE_SET,
|
||||||
self.kodicursor)
|
self.kodicursor)
|
||||||
self.kodi_db.assignBoxset(setid, kodiId)
|
self.kodi_db.assignBoxset(setid, kodi_id)
|
||||||
|
return True
|
||||||
|
|
||||||
def updateUserdata(self, xml, viewtag=None, viewid=None):
|
def updateUserdata(self, xml, viewtag=None, viewid=None):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -267,10 +267,9 @@ class ProcessFanartThread(Thread):
|
||||||
queue Queue.Queue() object that you will need to fill with
|
queue Queue.Queue() object that you will need to fill with
|
||||||
dicts of the following form:
|
dicts of the following form:
|
||||||
{
|
{
|
||||||
'itemId': the Plex id as a string
|
'plex_id': the Plex id as a string
|
||||||
'class': the itemtypes class, e.g. 'Movies'
|
'plex_type': the Plex media type, e.g. 'movie'
|
||||||
'mediaType': the kodi media type, e.g. 'movie'
|
'refresh': True/False if True, will overwrite any 3rd party
|
||||||
'refresh': True/False if true, will overwrite any 3rd party
|
|
||||||
fanart. If False, will only get missing
|
fanart. If False, will only get missing
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
@ -298,57 +297,17 @@ class ProcessFanartThread(Thread):
|
||||||
except Queue.Empty:
|
except Queue.Empty:
|
||||||
xbmc.sleep(200)
|
xbmc.sleep(200)
|
||||||
continue
|
continue
|
||||||
with plexdb.Get_Plex_DB() as plex_db:
|
|
||||||
try:
|
|
||||||
kodiId = plex_db.getItem_byId(item['itemId'])[0]
|
|
||||||
except TypeError:
|
|
||||||
log.error('Could not get Kodi id for plex id %s'
|
|
||||||
% item['itemId'])
|
|
||||||
queue.task_done()
|
|
||||||
continue
|
|
||||||
if item['refresh'] is True:
|
|
||||||
# Leave the Plex art untouched
|
|
||||||
allartworks = None
|
|
||||||
else:
|
|
||||||
with kodidb.GetKodiDB('video') as kodi_db:
|
|
||||||
allartworks = kodi_db.existingArt(kodiId,
|
|
||||||
item['mediaType'])
|
|
||||||
# Check if we even need to get additional art
|
|
||||||
needsupdate = False
|
|
||||||
for key, value in allartworks.iteritems():
|
|
||||||
if not value and not key == 'BoxRear':
|
|
||||||
needsupdate = True
|
|
||||||
break
|
|
||||||
if needsupdate is False:
|
|
||||||
log.debug('Already got all art for Plex id %s'
|
|
||||||
% item['itemId'])
|
|
||||||
queue.task_done()
|
|
||||||
continue
|
|
||||||
|
|
||||||
log.debug('Getting additional fanart for Plex id %s'
|
log.debug('Get additional fanart for Plex id %s' % item['plex_id'])
|
||||||
% item['itemId'])
|
with getattr(itemtypes,
|
||||||
# Download Metadata
|
v.ITEMTYPE_FROM_PLEXTYPE[item['plex_type']])() as cls:
|
||||||
xml = GetPlexMetadata(item['itemId'])
|
result = cls.getfanart(item['plex_id'],
|
||||||
if xml is None:
|
refresh=item['refresh'])
|
||||||
# Did not receive a valid XML - skip that item for now
|
if result is True:
|
||||||
log.warn("Could not get metadata for %s. Skipping that item "
|
log.debug('Done getting fanart for Plex id %s'
|
||||||
"for now" % item['itemId'])
|
% item['plex_id'])
|
||||||
queue.task_done()
|
with plexdb.Get_Plex_DB() as plex_db:
|
||||||
continue
|
plex_db.set_fanart_synched(item['plex_id'])
|
||||||
elif xml == 401:
|
|
||||||
log.warn('HTTP 401 returned by PMS. Too much strain? '
|
|
||||||
'Cancelling sync for now')
|
|
||||||
# Kill remaining items in queue (for main thread to cont.)
|
|
||||||
queue.task_done()
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Do the work
|
|
||||||
with getattr(itemtypes, item['class'])() as cls:
|
|
||||||
cls.getfanart(xml[0], kodiId, item['mediaType'], allartworks)
|
|
||||||
# signals to queue job is done
|
|
||||||
log.debug('Done getting fanart for Plex id %s' % item['itemId'])
|
|
||||||
with plexdb.Get_Plex_DB() as plex_db:
|
|
||||||
plex_db.set_fanart_synched(item['itemId'])
|
|
||||||
queue.task_done()
|
queue.task_done()
|
||||||
log.info("---===### Stopped FanartSync ###===---")
|
log.info("---===### Stopped FanartSync ###===---")
|
||||||
|
|
||||||
|
@ -1071,15 +1030,11 @@ class LibrarySync(Thread):
|
||||||
log.info("Sync threads finished")
|
log.info("Sync threads finished")
|
||||||
if (settings('FanartTV') == 'true' and
|
if (settings('FanartTV') == 'true' and
|
||||||
itemType in ('Movies', 'TVShows')):
|
itemType in ('Movies', 'TVShows')):
|
||||||
# Save to queue for later processing
|
|
||||||
typus = {'Movies': v.KODI_TYPE_MOVIE,
|
|
||||||
'TVShows': v.KODI_TYPE_SHOW}[itemType]
|
|
||||||
for item in self.updatelist:
|
for item in self.updatelist:
|
||||||
if item['mediaType'] in (v.KODI_TYPE_MOVIE, v.KODI_TYPE_SHOW):
|
if item['mediaType'] in (v.PLEX_TYPE_MOVIE, v.PLEX_TYPE_SHOW):
|
||||||
self.fanartqueue.put({
|
self.fanartqueue.put({
|
||||||
'itemId': item['itemId'],
|
'plex_id': item['itemId'],
|
||||||
'class': itemType,
|
'plex_type': item['mediaType'],
|
||||||
'mediaType': typus,
|
|
||||||
'refresh': False
|
'refresh': False
|
||||||
})
|
})
|
||||||
self.updatelist = []
|
self.updatelist = []
|
||||||
|
@ -1484,15 +1439,13 @@ class LibrarySync(Thread):
|
||||||
# processing the item. Do it later (excepting deletions)
|
# processing the item. Do it later (excepting deletions)
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
successful, item = self.process_newitems(item)
|
successful = self.process_newitems(item)
|
||||||
if successful and settings('FanartTV') == 'true':
|
if successful and settings('FanartTV') == 'true':
|
||||||
if item['mediatype'] in ('movie', 'show'):
|
plex_type = v.PLEX_TYPE_FROM_WEBSOCKET[item['type']]
|
||||||
mediaType = {'movie': 'Movie'}[item['mediatype']]
|
if plex_type in (v.PLEX_TYPE_MOVIE, v.PLEX_TYPE_SHOW):
|
||||||
cls = {'movie': 'Movies'}[item['mediatype']]
|
|
||||||
self.fanartqueue.put({
|
self.fanartqueue.put({
|
||||||
'itemId': item['ratingKey'],
|
'plex_id': item['ratingKey'],
|
||||||
'class': cls,
|
'plex_type': plex_type,
|
||||||
'mediaType': mediaType,
|
|
||||||
'refresh': False
|
'refresh': False
|
||||||
})
|
})
|
||||||
if successful is True:
|
if successful is True:
|
||||||
|
@ -1518,37 +1471,34 @@ class LibrarySync(Thread):
|
||||||
xbmc.executebuiltin('UpdateLibrary(music)')
|
xbmc.executebuiltin('UpdateLibrary(music)')
|
||||||
|
|
||||||
def process_newitems(self, item):
|
def process_newitems(self, item):
|
||||||
ratingKey = item['ratingKey']
|
xml = GetPlexMetadata(item['ratingKey'])
|
||||||
xml = GetPlexMetadata(ratingKey)
|
|
||||||
try:
|
try:
|
||||||
mediatype = xml[0].attrib['type']
|
mediatype = xml[0].attrib['type']
|
||||||
except (IndexError, KeyError, TypeError):
|
except (IndexError, KeyError, TypeError):
|
||||||
log.error('Could not download metadata for %s' % ratingKey)
|
log.error('Could not download metadata for %s' % item['ratingKey'])
|
||||||
return False, item
|
return False
|
||||||
log.debug("Processing new/updated PMS item: %s" % ratingKey)
|
log.debug("Processing new/updated PMS item: %s" % item['ratingKey'])
|
||||||
viewtag = xml.attrib.get('librarySectionTitle')
|
viewtag = xml.attrib.get('librarySectionTitle')
|
||||||
viewid = xml.attrib.get('librarySectionID')
|
viewid = xml.attrib.get('librarySectionID')
|
||||||
# Attach mediatype for later
|
if mediatype == v.PLEX_TYPE_MOVIE:
|
||||||
item['mediatype'] = mediatype
|
|
||||||
if mediatype == 'movie':
|
|
||||||
self.videoLibUpdate = True
|
self.videoLibUpdate = True
|
||||||
with itemtypes.Movies() as movie:
|
with itemtypes.Movies() as movie:
|
||||||
movie.add_update(xml[0],
|
movie.add_update(xml[0],
|
||||||
viewtag=viewtag,
|
viewtag=viewtag,
|
||||||
viewid=viewid)
|
viewid=viewid)
|
||||||
elif mediatype == 'episode':
|
elif mediatype == v.PLEX_TYPE_EPISODE:
|
||||||
self.videoLibUpdate = True
|
self.videoLibUpdate = True
|
||||||
with itemtypes.TVShows() as show:
|
with itemtypes.TVShows() as show:
|
||||||
show.add_updateEpisode(xml[0],
|
show.add_updateEpisode(xml[0],
|
||||||
viewtag=viewtag,
|
viewtag=viewtag,
|
||||||
viewid=viewid)
|
viewid=viewid)
|
||||||
elif mediatype == 'track':
|
elif mediatype == v.PLEX_TYPE_SONG:
|
||||||
self.musicLibUpdate = True
|
self.musicLibUpdate = True
|
||||||
with itemtypes.Music() as music:
|
with itemtypes.Music() as music:
|
||||||
music.add_updateSong(xml[0],
|
music.add_updateSong(xml[0],
|
||||||
viewtag=viewtag,
|
viewtag=viewtag,
|
||||||
viewid=viewid)
|
viewid=viewid)
|
||||||
return True, item
|
return True
|
||||||
|
|
||||||
def process_deleteditems(self, item):
|
def process_deleteditems(self, item):
|
||||||
if item.get('type') == 1:
|
if item.get('type') == 1:
|
||||||
|
@ -1713,20 +1663,15 @@ class LibrarySync(Thread):
|
||||||
refresh=True Force refresh all external fanart
|
refresh=True Force refresh all external fanart
|
||||||
"""
|
"""
|
||||||
items = []
|
items = []
|
||||||
typus = {
|
|
||||||
v.PLEX_TYPE_MOVIE: 'Movies',
|
|
||||||
v.PLEX_TYPE_SHOW: 'TVShows'
|
|
||||||
}
|
|
||||||
with plexdb.Get_Plex_DB() as plex_db:
|
with plexdb.Get_Plex_DB() as plex_db:
|
||||||
for plextype in typus:
|
for plex_type in (v.PLEX_TYPE_MOVIE, v.PLEX_TYPE_SHOW):
|
||||||
items.extend(plex_db.itemsByType(plextype))
|
items.extend(plex_db.itemsByType(plex_type))
|
||||||
# Shuffle the list to not always start out identically
|
# Shuffle the list to not always start out identically
|
||||||
shuffle(items)
|
shuffle(items)
|
||||||
for item in items:
|
for item in items:
|
||||||
self.fanartqueue.put({
|
self.fanartqueue.put({
|
||||||
'itemId': item['plexId'],
|
'plex_id': item['plex_id'],
|
||||||
'mediaType': item['kodi_type'],
|
'plex_type': item['plex_type'],
|
||||||
'class': typus[item['plex_type']],
|
|
||||||
'refresh': refresh
|
'refresh': refresh
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1843,10 +1788,8 @@ class LibrarySync(Thread):
|
||||||
% len(missing_fanart))
|
% len(missing_fanart))
|
||||||
for item in missing_fanart:
|
for item in missing_fanart:
|
||||||
self.fanartqueue.put({
|
self.fanartqueue.put({
|
||||||
'itemId': item['plex_id'],
|
'plex_id': item['plex_id'],
|
||||||
'mediaType': item['kodi_type'],
|
'plex_type': item['plex_type'],
|
||||||
'class': v.ITEMTYPE_FROM_KODITYPE[
|
|
||||||
item['kodi_type']],
|
|
||||||
'refresh': True
|
'refresh': True
|
||||||
})
|
})
|
||||||
log.info('Refreshing video nodes and playlists now')
|
log.info('Refreshing video nodes and playlists now')
|
||||||
|
|
|
@ -396,7 +396,7 @@ class Plex_DB_Functions():
|
||||||
"""
|
"""
|
||||||
Returns a list of dicts for plex_type:
|
Returns a list of dicts for plex_type:
|
||||||
{
|
{
|
||||||
'plexId': plex_id
|
'plex_id': plex_id
|
||||||
'kodiId': kodi_id
|
'kodiId': kodi_id
|
||||||
'kodi_type': kodi_type
|
'kodi_type': kodi_type
|
||||||
'plex_type': plex_type
|
'plex_type': plex_type
|
||||||
|
@ -411,7 +411,7 @@ class Plex_DB_Functions():
|
||||||
result = []
|
result = []
|
||||||
for row in self.plexcursor.fetchall():
|
for row in self.plexcursor.fetchall():
|
||||||
result.append({
|
result.append({
|
||||||
'plexId': row[0],
|
'plex_id': row[0],
|
||||||
'kodiId': row[1],
|
'kodiId': row[1],
|
||||||
'kodi_type': row[2],
|
'kodi_type': row[2],
|
||||||
'plex_type': plex_type
|
'plex_type': plex_type
|
||||||
|
@ -427,13 +427,13 @@ class Plex_DB_Functions():
|
||||||
|
|
||||||
def get_missing_fanart(self):
|
def get_missing_fanart(self):
|
||||||
"""
|
"""
|
||||||
Returns a list of {'plex_id': x, 'kodi_type': y} where fanart_synced
|
Returns a list of {'plex_id': x, 'plex_type': y} where fanart_synced
|
||||||
flag is set to 0
|
flag is set to 0
|
||||||
|
|
||||||
This only for plex_type is either movie or TV show
|
This only for plex_type is either movie or TV show
|
||||||
"""
|
"""
|
||||||
query = '''
|
query = '''
|
||||||
SELECT plex_id, kodi_type FROM plex
|
SELECT plex_id, plex_type FROM plex
|
||||||
WHERE fanart_synced = ?
|
WHERE fanart_synced = ?
|
||||||
AND (plex_type = ? OR plex_type = ?)
|
AND (plex_type = ? OR plex_type = ?)
|
||||||
'''
|
'''
|
||||||
|
@ -443,5 +443,5 @@ class Plex_DB_Functions():
|
||||||
result = []
|
result = []
|
||||||
for row in rows:
|
for row in rows:
|
||||||
result.append({'plex_id': row[0],
|
result.append({'plex_id': row[0],
|
||||||
'kodi_type': row[1]})
|
'plex_type': row[1]})
|
||||||
return result
|
return result
|
||||||
|
|
|
@ -221,6 +221,18 @@ REMAP_TYPE_FROM_PLEXTYPE = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PLEX_TYPE_FROM_WEBSOCKET = {
|
||||||
|
1: PLEX_TYPE_MOVIE,
|
||||||
|
2: PLEX_TYPE_SHOW,
|
||||||
|
3: PLEX_TYPE_SEASON,
|
||||||
|
4: PLEX_TYPE_EPISODE,
|
||||||
|
8: PLEX_TYPE_ARTIST,
|
||||||
|
9: PLEX_TYPE_ALBUM,
|
||||||
|
10: PLEX_TYPE_SONG,
|
||||||
|
12: PLEX_TYPE_CLIP
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# extensions from:
|
# extensions from:
|
||||||
# http://kodi.wiki/view/Features_and_supported_codecs#Format_support (RAW image
|
# http://kodi.wiki/view/Features_and_supported_codecs#Format_support (RAW image
|
||||||
# formats, BMP, JPEG, GIF, PNG, TIFF, MNG, ICO, PCX and Targa/TGA)
|
# formats, BMP, JPEG, GIF, PNG, TIFF, MNG, ICO, PCX and Targa/TGA)
|
||||||
|
|
Loading…
Reference in a new issue