diff --git a/resources/language/resource.language.en_gb/strings.po b/resources/language/resource.language.en_gb/strings.po index db179cee..e62c76dc 100644 --- a/resources/language/resource.language.en_gb/strings.po +++ b/resources/language/resource.language.en_gb/strings.po @@ -41,6 +41,26 @@ msgctxt "#30005" msgid "Username: " msgstr "" +# Sync notification displayed if there is still artwork to be cached to Kodi +msgctxt "#30006" +msgid "Caching %s images" +msgstr "" + +# Sync notification displayed if syncing of major artwork is done +msgctxt "#30007" +msgid "Major image caching done" +msgstr "" + +# PKC settings artwork: Enable notifications for artwork image sync +msgctxt "#30008" +msgid "Enable notifications for image caching" +msgstr "" + +# PKC settings artwork: Enable image caching during Kodi playback +msgctxt "#30009" +msgid "Enable image caching during Kodi playback (restart Kodi!)" +msgstr "" + # Button text msgctxt "#30012" msgid "OK" diff --git a/resources/lib/artwork.py b/resources/lib/artwork.py index 1c39b806..84d7b612 100644 --- a/resources/lib/artwork.py +++ b/resources/lib/artwork.py @@ -22,6 +22,10 @@ LOG = getLogger("PLEX." + __name__) # Disable annoying requests warnings requests.packages.urllib3.disable_warnings() ARTWORK_QUEUE = Queue() +IMAGE_CACHING_SUSPENDS = ['SUSPEND_LIBRARY_THREAD', 'DB_SCAN', 'STOP_SYNC'] +if not settings('imageSyncDuringPlayback') == 'true': + IMAGE_CACHING_SUSPENDS.append('SUSPEND_SYNC') + ############################################################################### @@ -33,11 +37,9 @@ def double_urldecode(text): return unquote(unquote(text)) -@thread_methods(add_suspends=['SUSPEND_LIBRARY_THREAD', - 'DB_SCAN', - 'STOP_SYNC']) +@thread_methods(add_suspends=IMAGE_CACHING_SUSPENDS) class Image_Cache_Thread(Thread): - sleep_between = 50 + sleep_between = 200 # Potentially issues with limited number of threads # Hence let Kodi wait till download is successful timeout = (35.1, 35.1) @@ -47,6 +49,7 @@ class Image_Cache_Thread(Thread): Thread.__init__(self) def run(self): + LOG.info("---===### Starting Image_Cache_Thread ###===---") stopped = self.stopped suspended = self.suspended queue = self.queue @@ -65,6 +68,16 @@ class Image_Cache_Thread(Thread): except Empty: sleep(1000) continue + if isinstance(url, ArtworkSyncMessage): + if state.IMAGE_SYNC_NOTIFICATIONS: + dialog('notification', + heading=lang(29999), + message=url.message, + icon='{plex}', + sound=False) + queue.task_done() + continue + url = double_urlencode(try_encode(url)) sleeptime = 0 while True: try: @@ -116,6 +129,44 @@ class Artwork(): if enableTextureCache: queue = ARTWORK_QUEUE + def cache_major_artwork(self): + """ + Takes the existing Kodi library and caches posters and fanart. + Necessary because otherwise PKC caches artwork e.g. from fanart.tv + which basically blocks Kodi from getting needed artwork fast (e.g. + while browsing the library) + """ + if not self.enableTextureCache: + return + artworks = list() + # Get all posters and fanart/background for video and music + for kind in ('video', 'music'): + connection = kodi_sql(kind) + cursor = connection.cursor() + for typus in ('poster', 'fanart'): + cursor.execute('SELECT url FROM art WHERE type == ?', + (typus, )) + artworks.extend(cursor.fetchall()) + connection.close() + artworks_to_cache = list() + connection = kodi_sql('texture') + cursor = connection.cursor() + for url in artworks: + query = 'SELECT url FROM texture WHERE url == ? LIMIT 1' + cursor.execute(query, (url[0], )) + if not cursor.fetchone(): + artworks_to_cache.append(url) + connection.close() + if not artworks_to_cache: + LOG.info('Caching of major images to Kodi texture cache done') + return + LOG.info('Caching has not been completed - caching %s major images', + len(artworks_to_cache)) + self.queue.put(ArtworkSyncMessage(lang(30006) % len(artworks_to_cache))) + for url in artworks_to_cache: + self.queue.put(url[0]) + self.queue.put(ArtworkSyncMessage(lang(30007))) + def fullTextureCacheSync(self): """ This method will sync all Kodi artwork to textures13.db @@ -174,10 +225,10 @@ class Artwork(): def cache_texture(self, url): ''' - Cache a single image url to the texture cache + Cache a single image url to the texture cache. url: unicode ''' if url and self.enableTextureCache: - self.queue.put(double_urlencode(try_encode(url))) + self.queue.put(url) def modify_artwork(self, artworks, kodi_id, kodi_type, cursor): """ @@ -266,3 +317,11 @@ class Artwork(): for path in paths: makedirs(try_decode(translatePath("special://thumbnails/%s" % path))) + + +class ArtworkSyncMessage(object): + """ + Put in artwork queue to display the message as a Kodi notification + """ + def __init__(self, message): + self.message = message diff --git a/resources/lib/entrypoint.py b/resources/lib/entrypoint.py index 1bd5318e..7ec66d72 100644 --- a/resources/lib/entrypoint.py +++ b/resources/lib/entrypoint.py @@ -369,7 +369,7 @@ def getRecentEpisodes(viewid, mediatype, tagname, limit): append_show_title = settings('RecentTvAppendShow') == 'true' append_sxxexx = settings('RecentTvAppendSeason') == 'true' # First we get a list of all the TV shows - filtered by tag - allshowsIds = set() + allshowsIds = list() params = { 'sort': {'order': "descending", 'method': "dateadded"}, 'filter': {'operator': "is", 'field': "tag", 'value': "%s" % tagname}, diff --git a/resources/lib/kodimonitor.py b/resources/lib/kodimonitor.py index a7c3dd65..a35af585 100644 --- a/resources/lib/kodimonitor.py +++ b/resources/lib/kodimonitor.py @@ -50,7 +50,8 @@ STATE_SETTINGS = { 'remapSMBphotoNew': 'remapSMBphotoNew', 'enableMusic': 'ENABLE_MUSIC', 'forceReloadSkinOnPlaybackStop': 'FORCE_RELOAD_SKIN', - 'fetch_pms_item_number': 'FETCH_PMS_ITEM_NUMBER' + 'fetch_pms_item_number': 'FETCH_PMS_ITEM_NUMBER', + 'imageSyncNotifications': 'IMAGE_SYNC_NOTIFICATIONS' } ############################################################################### diff --git a/resources/lib/librarysync.py b/resources/lib/librarysync.py index 5ce7485e..a857c586 100644 --- a/resources/lib/librarysync.py +++ b/resources/lib/librarysync.py @@ -16,6 +16,7 @@ from downloadutils import DownloadUtils as DU import itemtypes import plexdb_functions as plexdb import kodidb_functions as kodidb +import artwork import videonodes import variables as v @@ -1463,7 +1464,6 @@ class LibrarySync(Thread): elif state.RUN_LIB_SCAN == 'textures': state.DB_SCAN = True window('plex_dbScan', value="true") - import artwork artwork.Artwork().fullTextureCacheSync() window('plex_dbScan', clear=True) state.DB_SCAN = False @@ -1527,8 +1527,6 @@ class LibrarySync(Thread): last_time_sync = utils.unix_timestamp() window('plex_dbScan', clear=True) state.DB_SCAN = False - # Start the fanart download thread - self.fanartthread.start() kodi_playlist_monitor = None while not self.stopped(): @@ -1555,6 +1553,7 @@ class LibrarySync(Thread): initial_sync_done = True kodi_db_version_checked = True last_sync = utils.unix_timestamp() + self.fanartthread.start() else: LOG.error('Initial start-up full sync unsuccessful') xbmc.executebuiltin('InhibitIdleShutdown(false)') @@ -1599,6 +1598,8 @@ class LibrarySync(Thread): if settings('FanartTV') == 'true': self.sync_fanart() LOG.info('Done initial sync on Kodi startup') + artwork.Artwork().cache_major_artwork() + self.fanartthread.start() else: LOG.info('Startup sync has not yet been successful') window('plex_dbScan', clear=True) diff --git a/resources/lib/state.py b/resources/lib/state.py index 69532239..60b15ede 100644 --- a/resources/lib/state.py +++ b/resources/lib/state.py @@ -39,6 +39,8 @@ FORCE_RELOAD_SKIN = True # Stemming from the PKC settings.xml # Shall we show Kodi dialogs when synching? SYNC_DIALOG = True +# Shall Kodi show dialogs for syncing/caching images? (e.g. images left to sync) +IMAGE_SYNC_NOTIFICATIONS = True # Is synching of Plex music enabled? ENABLE_MUSIC = True # How often shall we sync? diff --git a/resources/settings.xml b/resources/settings.xml index fea2ad2d..d8e46400 100644 --- a/resources/settings.xml +++ b/resources/settings.xml @@ -125,6 +125,8 @@ + +