PlexKodiConnect/resources/lib/library_sync/fanart.py

168 lines
6.2 KiB
Python
Raw Normal View History

2017-04-03 01:02:41 +10:00
# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, unicode_literals
2017-04-03 01:02:41 +10:00
from logging import getLogger
2018-11-03 20:36:37 +11:00
from . import common
from ..plex_api import API
2018-10-24 19:57:52 +11:00
from ..plex_db import PlexDB
2018-11-09 07:22:16 +11:00
from ..kodi_db import KodiVideoDB
from .. import backgroundthread, utils
2018-11-19 00:59:17 +11:00
from .. import itemtypes, plex_functions as PF, variables as v, app
2017-04-03 01:02:41 +10:00
2018-11-02 01:43:27 +11:00
LOG = getLogger('PLEX.sync.fanart')
2017-04-03 01:02:41 +10:00
2018-11-03 20:36:37 +11:00
SUPPORTED_TYPES = (v.PLEX_TYPE_MOVIE, v.PLEX_TYPE_SHOW)
2018-11-02 01:43:27 +11:00
SYNC_FANART = utils.settings('FanartTV') == 'true'
2018-11-03 20:36:37 +11:00
PREFER_KODI_COLLECTION_ART = utils.settings('PreferKodiCollectionArt') == 'false'
2018-12-26 05:12:49 +11:00
BATCH_SIZE = 500
2017-04-03 01:02:41 +10:00
def suspends():
return (app.APP.suspend_threads or
app.SYNC.stop_sync or
app.SYNC.db_scan or
app.SYNC.suspend_sync)
2018-11-03 20:36:37 +11:00
class FanartThread(backgroundthread.KillableThread):
2017-04-03 01:02:41 +10:00
"""
2018-11-03 20:36:37 +11:00
This will potentially take hours!
2017-04-03 01:02:41 +10:00
"""
2018-11-03 20:36:37 +11:00
def __init__(self, callback, refresh=False):
self.callback = callback
self.refresh = refresh
super(FanartThread, self).__init__()
2018-10-24 19:57:52 +11:00
def isSuspended(self):
return suspends()
2017-04-03 01:02:41 +10:00
def run(self):
2018-10-24 19:57:52 +11:00
try:
2018-11-03 20:36:37 +11:00
self._run_internal()
2018-10-24 19:57:52 +11:00
except:
2018-11-04 02:53:56 +11:00
utils.ERROR(notify=True)
2018-10-24 19:57:52 +11:00
2018-11-03 20:36:37 +11:00
def _run_internal(self):
LOG.info('Starting FanartThread')
finished = False
2018-12-26 05:12:49 +11:00
try:
for typus in SUPPORTED_TYPES:
offset = 0
while True:
with PlexDB() as plexdb:
# Keep DB connection open only for a short period of time!
if self.refresh:
batch = list(plexdb.every_plex_id(typus,
offset,
BATCH_SIZE))
else:
batch = list(plexdb.missing_fanart(typus,
offset,
BATCH_SIZE))
for plex_id in batch:
# Do the actual, time-consuming processing
if self.isCanceled():
return
if self.isSuspended():
if self.isCanceled():
return
app.APP.monitor.waitForAbort(1)
process_fanart(plex_id, typus, self.refresh)
2018-12-26 05:12:49 +11:00
if len(batch) < BATCH_SIZE:
break
2018-12-26 05:12:49 +11:00
offset += BATCH_SIZE
else:
finished = True
finally:
LOG.info('FanartThread finished: %s', finished)
self.callback(finished)
2018-10-24 19:57:52 +11:00
2018-11-03 20:36:37 +11:00
2018-11-27 03:58:15 +11:00
class FanartTask(common.libsync_mixin, backgroundthread.Task):
2018-11-03 20:36:37 +11:00
"""
This task will also be executed while library sync is suspended!
"""
def setup(self, plex_id, plex_type, refresh=False):
self.plex_id = plex_id
self.plex_type = plex_type
self.refresh = refresh
def run(self):
process_fanart(self.plex_id, self.plex_type, self.refresh)
2018-11-03 20:36:37 +11:00
def process_fanart(plex_id, plex_type, refresh=False):
"""
Will look for additional fanart for the plex_type item with plex_id.
Will check if we already got all artwork and only look if some are indeed
missing.
Will set the fanart_synced flag in the Plex DB if successful.
"""
done = False
try:
artworks = None
2018-11-03 20:36:37 +11:00
with PlexDB() as plexdb:
db_item = plexdb.item_by_id(plex_id,
plex_type)
2018-10-24 19:57:52 +11:00
if not db_item:
2018-11-03 20:36:37 +11:00
LOG.error('Could not get Kodi id for plex id %s', plex_id)
return
2018-11-03 20:36:37 +11:00
if not refresh:
2018-11-09 07:22:16 +11:00
with KodiVideoDB() as kodidb:
artworks = kodidb.get_art(db_item['kodi_id'],
db_item['kodi_type'])
# Check if we even need to get additional art
for key in v.ALL_KODI_ARTWORK:
if key not in artworks:
break
else:
done = True
return
2018-11-03 20:36:37 +11:00
xml = PF.GetPlexMetadata(plex_id)
try:
xml[0].attrib
except (TypeError, IndexError, AttributeError):
LOG.warn('Could not get metadata for %s. Skipping that item '
'for now', plex_id)
return
api = API(xml[0])
if artworks is None:
artworks = api.artwork()
# Get additional missing artwork from fanart artwork sites
artworks = api.fanart_artwork(artworks)
2018-11-04 03:04:24 +11:00
with itemtypes.ITEMTYPE_FROM_PLEXTYPE[plex_type](None) as context:
2018-10-24 19:57:52 +11:00
context.set_fanart(artworks,
db_item['kodi_id'],
db_item['kodi_type'])
# Additional fanart for sets/collections
2018-11-03 20:36:37 +11:00
if plex_type == v.PLEX_TYPE_MOVIE:
for _, setname in api.collection_list():
LOG.debug('Getting artwork for movie set %s', setname)
2018-11-09 07:22:16 +11:00
with KodiVideoDB() as kodidb:
setid = kodidb.create_collection(setname)
external_set_artwork = api.set_artwork()
2018-11-03 20:36:37 +11:00
if external_set_artwork and PREFER_KODI_COLLECTION_ART:
kodi_artwork = api.artwork(kodi_id=setid,
kodi_type=v.KODI_TYPE_SET)
for art in kodi_artwork:
if art in external_set_artwork:
del external_set_artwork[art]
2018-11-05 22:24:18 +11:00
with itemtypes.Movie(None) as movie:
2018-11-22 18:04:41 +11:00
movie.kodidb.modify_artwork(external_set_artwork,
setid,
v.KODI_TYPE_SET)
done = True
except utils.OperationalError:
# We were not fast enough when a sync started
pass
finally:
if done is True and not suspends():
try:
with PlexDB() as plexdb:
plexdb.set_fanart_synced(plex_id,
plex_type)
except utils.OperationalError:
# We were not fast enough when a sync started
pass