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
|
||||
|
||||
@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:
|
||||
allartworks = API.getAllArtwork()
|
||||
self.artwork.addArtwork(API.getFanartArtwork(allartworks),
|
||||
kodiId,
|
||||
mediaType,
|
||||
kodi_id,
|
||||
kodi_type,
|
||||
self.kodicursor)
|
||||
# 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():
|
||||
log.debug('Getting artwork for movie set %s' % setname)
|
||||
setid = self.kodi_db.createBoxset(setname)
|
||||
|
@ -82,7 +121,8 @@ class Items(object):
|
|||
setid,
|
||||
v.KODI_TYPE_SET,
|
||||
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):
|
||||
"""
|
||||
|
|
|
@ -267,10 +267,9 @@ class ProcessFanartThread(Thread):
|
|||
queue Queue.Queue() object that you will need to fill with
|
||||
dicts of the following form:
|
||||
{
|
||||
'itemId': the Plex id as a string
|
||||
'class': the itemtypes class, e.g. 'Movies'
|
||||
'mediaType': the kodi media type, e.g. 'movie'
|
||||
'refresh': True/False if true, will overwrite any 3rd party
|
||||
'plex_id': the Plex id as a string
|
||||
'plex_type': the Plex media type, e.g. 'movie'
|
||||
'refresh': True/False if True, will overwrite any 3rd party
|
||||
fanart. If False, will only get missing
|
||||
}
|
||||
"""
|
||||
|
@ -298,57 +297,17 @@ class ProcessFanartThread(Thread):
|
|||
except Queue.Empty:
|
||||
xbmc.sleep(200)
|
||||
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'
|
||||
% item['itemId'])
|
||||
# Download Metadata
|
||||
xml = GetPlexMetadata(item['itemId'])
|
||||
if xml is None:
|
||||
# Did not receive a valid XML - skip that item for now
|
||||
log.warn("Could not get metadata for %s. Skipping that item "
|
||||
"for now" % item['itemId'])
|
||||
queue.task_done()
|
||||
continue
|
||||
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'])
|
||||
log.debug('Get additional fanart for Plex id %s' % item['plex_id'])
|
||||
with getattr(itemtypes,
|
||||
v.ITEMTYPE_FROM_PLEXTYPE[item['plex_type']])() as cls:
|
||||
result = cls.getfanart(item['plex_id'],
|
||||
refresh=item['refresh'])
|
||||
if result is True:
|
||||
log.debug('Done getting fanart for Plex id %s'
|
||||
% item['plex_id'])
|
||||
with plexdb.Get_Plex_DB() as plex_db:
|
||||
plex_db.set_fanart_synched(item['itemId'])
|
||||
plex_db.set_fanart_synched(item['plex_id'])
|
||||
queue.task_done()
|
||||
log.info("---===### Stopped FanartSync ###===---")
|
||||
|
||||
|
@ -1071,15 +1030,11 @@ class LibrarySync(Thread):
|
|||
log.info("Sync threads finished")
|
||||
if (settings('FanartTV') == 'true' and
|
||||
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:
|
||||
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({
|
||||
'itemId': item['itemId'],
|
||||
'class': itemType,
|
||||
'mediaType': typus,
|
||||
'plex_id': item['itemId'],
|
||||
'plex_type': item['mediaType'],
|
||||
'refresh': False
|
||||
})
|
||||
self.updatelist = []
|
||||
|
@ -1484,15 +1439,13 @@ class LibrarySync(Thread):
|
|||
# processing the item. Do it later (excepting deletions)
|
||||
continue
|
||||
else:
|
||||
successful, item = self.process_newitems(item)
|
||||
successful = self.process_newitems(item)
|
||||
if successful and settings('FanartTV') == 'true':
|
||||
if item['mediatype'] in ('movie', 'show'):
|
||||
mediaType = {'movie': 'Movie'}[item['mediatype']]
|
||||
cls = {'movie': 'Movies'}[item['mediatype']]
|
||||
plex_type = v.PLEX_TYPE_FROM_WEBSOCKET[item['type']]
|
||||
if plex_type in (v.PLEX_TYPE_MOVIE, v.PLEX_TYPE_SHOW):
|
||||
self.fanartqueue.put({
|
||||
'itemId': item['ratingKey'],
|
||||
'class': cls,
|
||||
'mediaType': mediaType,
|
||||
'plex_id': item['ratingKey'],
|
||||
'plex_type': plex_type,
|
||||
'refresh': False
|
||||
})
|
||||
if successful is True:
|
||||
|
@ -1518,37 +1471,34 @@ class LibrarySync(Thread):
|
|||
xbmc.executebuiltin('UpdateLibrary(music)')
|
||||
|
||||
def process_newitems(self, item):
|
||||
ratingKey = item['ratingKey']
|
||||
xml = GetPlexMetadata(ratingKey)
|
||||
xml = GetPlexMetadata(item['ratingKey'])
|
||||
try:
|
||||
mediatype = xml[0].attrib['type']
|
||||
except (IndexError, KeyError, TypeError):
|
||||
log.error('Could not download metadata for %s' % ratingKey)
|
||||
return False, item
|
||||
log.debug("Processing new/updated PMS item: %s" % ratingKey)
|
||||
log.error('Could not download metadata for %s' % item['ratingKey'])
|
||||
return False
|
||||
log.debug("Processing new/updated PMS item: %s" % item['ratingKey'])
|
||||
viewtag = xml.attrib.get('librarySectionTitle')
|
||||
viewid = xml.attrib.get('librarySectionID')
|
||||
# Attach mediatype for later
|
||||
item['mediatype'] = mediatype
|
||||
if mediatype == 'movie':
|
||||
if mediatype == v.PLEX_TYPE_MOVIE:
|
||||
self.videoLibUpdate = True
|
||||
with itemtypes.Movies() as movie:
|
||||
movie.add_update(xml[0],
|
||||
viewtag=viewtag,
|
||||
viewid=viewid)
|
||||
elif mediatype == 'episode':
|
||||
elif mediatype == v.PLEX_TYPE_EPISODE:
|
||||
self.videoLibUpdate = True
|
||||
with itemtypes.TVShows() as show:
|
||||
show.add_updateEpisode(xml[0],
|
||||
viewtag=viewtag,
|
||||
viewid=viewid)
|
||||
elif mediatype == 'track':
|
||||
elif mediatype == v.PLEX_TYPE_SONG:
|
||||
self.musicLibUpdate = True
|
||||
with itemtypes.Music() as music:
|
||||
music.add_updateSong(xml[0],
|
||||
viewtag=viewtag,
|
||||
viewid=viewid)
|
||||
return True, item
|
||||
return True
|
||||
|
||||
def process_deleteditems(self, item):
|
||||
if item.get('type') == 1:
|
||||
|
@ -1713,20 +1663,15 @@ class LibrarySync(Thread):
|
|||
refresh=True Force refresh all external fanart
|
||||
"""
|
||||
items = []
|
||||
typus = {
|
||||
v.PLEX_TYPE_MOVIE: 'Movies',
|
||||
v.PLEX_TYPE_SHOW: 'TVShows'
|
||||
}
|
||||
with plexdb.Get_Plex_DB() as plex_db:
|
||||
for plextype in typus:
|
||||
items.extend(plex_db.itemsByType(plextype))
|
||||
for plex_type in (v.PLEX_TYPE_MOVIE, v.PLEX_TYPE_SHOW):
|
||||
items.extend(plex_db.itemsByType(plex_type))
|
||||
# Shuffle the list to not always start out identically
|
||||
shuffle(items)
|
||||
for item in items:
|
||||
self.fanartqueue.put({
|
||||
'itemId': item['plexId'],
|
||||
'mediaType': item['kodi_type'],
|
||||
'class': typus[item['plex_type']],
|
||||
'plex_id': item['plex_id'],
|
||||
'plex_type': item['plex_type'],
|
||||
'refresh': refresh
|
||||
})
|
||||
|
||||
|
@ -1843,10 +1788,8 @@ class LibrarySync(Thread):
|
|||
% len(missing_fanart))
|
||||
for item in missing_fanart:
|
||||
self.fanartqueue.put({
|
||||
'itemId': item['plex_id'],
|
||||
'mediaType': item['kodi_type'],
|
||||
'class': v.ITEMTYPE_FROM_KODITYPE[
|
||||
item['kodi_type']],
|
||||
'plex_id': item['plex_id'],
|
||||
'plex_type': item['plex_type'],
|
||||
'refresh': True
|
||||
})
|
||||
log.info('Refreshing video nodes and playlists now')
|
||||
|
|
|
@ -396,7 +396,7 @@ class Plex_DB_Functions():
|
|||
"""
|
||||
Returns a list of dicts for plex_type:
|
||||
{
|
||||
'plexId': plex_id
|
||||
'plex_id': plex_id
|
||||
'kodiId': kodi_id
|
||||
'kodi_type': kodi_type
|
||||
'plex_type': plex_type
|
||||
|
@ -411,7 +411,7 @@ class Plex_DB_Functions():
|
|||
result = []
|
||||
for row in self.plexcursor.fetchall():
|
||||
result.append({
|
||||
'plexId': row[0],
|
||||
'plex_id': row[0],
|
||||
'kodiId': row[1],
|
||||
'kodi_type': row[2],
|
||||
'plex_type': plex_type
|
||||
|
@ -427,13 +427,13 @@ class Plex_DB_Functions():
|
|||
|
||||
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
|
||||
|
||||
This only for plex_type is either movie or TV show
|
||||
"""
|
||||
query = '''
|
||||
SELECT plex_id, kodi_type FROM plex
|
||||
SELECT plex_id, plex_type FROM plex
|
||||
WHERE fanart_synced = ?
|
||||
AND (plex_type = ? OR plex_type = ?)
|
||||
'''
|
||||
|
@ -443,5 +443,5 @@ class Plex_DB_Functions():
|
|||
result = []
|
||||
for row in rows:
|
||||
result.append({'plex_id': row[0],
|
||||
'kodi_type': row[1]})
|
||||
'plex_type': row[1]})
|
||||
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:
|
||||
# http://kodi.wiki/view/Features_and_supported_codecs#Format_support (RAW image
|
||||
# formats, BMP, JPEG, GIF, PNG, TIFF, MNG, ICO, PCX and Targa/TGA)
|
||||
|
|
Loading…
Reference in a new issue