From cdf78de132a4447da369b147a5318d27434e7657 Mon Sep 17 00:00:00 2001 From: Marcel van der Veldt Date: Sat, 6 Jun 2015 00:11:24 +0200 Subject: [PATCH] added support for kodi texturecache: - setting in addon settings to turn on the cache feature (now for testing, maybe hidden later) - for all new items the poster and the fanart image will be cached automatically (when setting is on) - added a option to the plugin root options to perform full cache fill which will pull every single image to the cache. --- default.py | 4 ++ resources/lib/Entrypoint.py | 1 + resources/lib/LibrarySync.py | 1 - resources/lib/TextureCache.py | 105 ++++++++++++++++++++++++++++++ resources/lib/WriteKodiMusicDB.py | 7 +- resources/lib/WriteKodiVideoDB.py | 14 ++-- resources/settings.xml | 3 +- 7 files changed, 128 insertions(+), 7 deletions(-) create mode 100644 resources/lib/TextureCache.py diff --git a/default.py b/default.py index af514198..68d0294f 100644 --- a/default.py +++ b/default.py @@ -47,6 +47,10 @@ elif mode == "settings": elif mode == "manualsync": from LibrarySync import LibrarySync LibrarySync().FullLibrarySync(True) + +elif mode == "texturecache": + from TextureCache import TextureCache + TextureCache().FullTextureCacheSync() ##### BROWSE EMBY CHANNELS ROOT ##### elif mode == "channels": diff --git a/resources/lib/Entrypoint.py b/resources/lib/Entrypoint.py index f86af5d1..5cdf39f9 100644 --- a/resources/lib/Entrypoint.py +++ b/resources/lib/Entrypoint.py @@ -486,5 +486,6 @@ def doMainListing(): addDirectoryItem("Perform manual sync", "plugin://plugin.video.emby/?mode=manualsync") addDirectoryItem("Add user to session", "plugin://plugin.video.emby/?mode=adduser") addDirectoryItem("Perform local database reset (full resync)", "plugin://plugin.video.emby/?mode=reset") + addDirectoryItem("Cache all images to Kodi texture cache (advanced)", "plugin://plugin.video.emby/?mode=texturecache") xbmcplugin.endOfDirectory(int(sys.argv[1])) diff --git a/resources/lib/LibrarySync.py b/resources/lib/LibrarySync.py index 02a2dea8..5570cdf2 100644 --- a/resources/lib/LibrarySync.py +++ b/resources/lib/LibrarySync.py @@ -618,7 +618,6 @@ class LibrarySync(): xbmc.executebuiltin("UpdateLibrary(video)") WINDOW.setProperty("SyncDatabaseRunning", "false") - def ShouldStop(self): if(xbmc.abortRequested): diff --git a/resources/lib/TextureCache.py b/resources/lib/TextureCache.py new file mode 100644 index 00000000..e095cbec --- /dev/null +++ b/resources/lib/TextureCache.py @@ -0,0 +1,105 @@ +################################################################################################# +# TextureCache +################################################################################################# + + +import xbmc +import xbmcaddon +import json +import requests +import urllib + +import Utils as utils + +class TextureCache(): + + + xbmc_host = 'localhost' + xbmc_port = None + xbmc_username = None + xbmc_password = None + enableTextureCache = False + + def __init__(self): + + addon = xbmcaddon.Addon(id='plugin.video.emby') + self.enableTextureCache = addon.getSetting("enableTextureCache") == "true" + + if (not self.xbmc_port and self.enableTextureCache == True): + self.setKodiWebServerDetails() + + def double_urlencode(self, text): + text = self.single_urlencode(text) + text = self.single_urlencode(text) + return text + + def single_urlencode(self, text): + blah = urllib.urlencode({'blahblahblah':text}) + blah = blah[13:] + + return blah + + def FullTextureCacheSync(self): + #this method can be called from the plugin to sync all Kodi textures to the texture cache. + #Warning: this means that every image will be cached locally, this takes diskspace! + connection = utils.KodiSQL("video") + cursor = connection.cursor() + cursor.execute("SELECT url FROM art") + result = cursor.fetchall() + for url in result: + self.CacheTexture(url[0]) + + cursor.close() + + connection = utils.KodiSQL("music") + cursor = connection.cursor() + cursor.execute("SELECT url FROM art") + result = cursor.fetchall() + for url in result: + self.CacheTexture(url[0]) + + cursor.close() + + + def CacheTexture(self,url): + #cache a single image url to the texture cache + if url and self.enableTextureCache == True: + + utils.logMsg("cache texture for URL", "Processing : " + url) + # add image to texture cache by simply calling it at the http endpoint + url = self.double_urlencode(url) + try: + response = requests.head('http://' + self.xbmc_host + ':' + str(self.xbmc_port) + '/image/image://' + url, auth=(self.xbmc_username, self.xbmc_password),timeout=(0.01, 0.01)) + except: + #extreme short timeouts so we will have a exception, but we don't need the result so pass + pass + + + def setKodiWebServerDetails(self): + # Get the Kodi webserver details - used to set the texture cache + json_response = xbmc.executeJSONRPC('{"jsonrpc":"2.0", "id":1, "method":"Settings.GetSettingValue","params":{"setting":"services.webserver"}, "id":1}') + jsonobject = json.loads(json_response.decode('utf-8','replace')) + if(jsonobject.has_key('result')): + xbmc_webserver_enabled = jsonobject["result"]["value"] + + if not xbmc_webserver_enabled: + #enable the webserver if not enabled + xbmc.executeJSONRPC('{"jsonrpc":"2.0", "id":1, "method":"Settings.SetSettingValue","params":{"setting":"services.webserverport","value":8080}, "id":1}') + self.xbmc_port = 8080 + xbmc.executeJSONRPC('{"jsonrpc":"2.0", "id":1, "method":"Settings.SetSettingValue","params":{"setting":"services.webserver","value":true}, "id":1}') + self.xbmc_port = "kodi" + + json_response = xbmc.executeJSONRPC('{"jsonrpc":"2.0", "id":1, "method":"Settings.GetSettingValue","params":{"setting":"services.webserverport"}, "id":1}') + jsonobject = json.loads(json_response.decode('utf-8','replace')) + if(jsonobject.has_key('result')): + self.xbmc_port = jsonobject["result"]["value"] + + json_response = xbmc.executeJSONRPC('{"jsonrpc":"2.0", "id":1, "method":"Settings.GetSettingValue","params":{"setting":"services.webserverusername"}, "id":1}') + jsonobject = json.loads(json_response.decode('utf-8','replace')) + if(jsonobject.has_key('result')): + self.xbmc_username = jsonobject["result"]["value"] + + json_response = xbmc.executeJSONRPC('{"jsonrpc":"2.0", "id":1, "method":"Settings.GetSettingValue","params":{"setting":"services.webserverpassword"}, "id":1}') + jsonobject = json.loads(json_response.decode('utf-8','replace')) + if(jsonobject.has_key('result')): + self.xbmc_password = jsonobject["result"]["value"] \ No newline at end of file diff --git a/resources/lib/WriteKodiMusicDB.py b/resources/lib/WriteKodiMusicDB.py index 2847e7c7..5d242b33 100644 --- a/resources/lib/WriteKodiMusicDB.py +++ b/resources/lib/WriteKodiMusicDB.py @@ -18,6 +18,7 @@ from DownloadUtils import DownloadUtils from PlayUtils import PlayUtils from ReadKodiDB import ReadKodiDB from ReadEmbyDB import ReadEmbyDB +from TextureCache import TextureCache from API import API import Utils as utils @@ -32,7 +33,7 @@ addondir = xbmc.translatePath(addon.getAddonInfo('profile')) class WriteKodiMusicDB(): - + textureCache = TextureCache() def updatePlayCountFromKodi(self, id, type, playcount=0): #when user marks item watched from kodi interface update this in Emby @@ -495,6 +496,10 @@ class WriteKodiMusicDB(): if(url != imageUrl): utils.logMsg("ArtworkSync", "Updating Art Link for kodiId: " + str(kodiId) + " (" + url + ") -> (" + imageUrl + ")") cursor.execute("UPDATE art set url = ? WHERE media_id = ? AND media_type = ? AND type = ?", (imageUrl, kodiId, mediaType, imageType)) + + #cache fanart textures in Kodi texture cache + if imageType == "fanart": + self.textureCache.CacheTexture(imageUrl) def AddGenresToMedia(self, id, genres, mediatype, cursor): diff --git a/resources/lib/WriteKodiVideoDB.py b/resources/lib/WriteKodiVideoDB.py index 26e9cd30..a5dbad8d 100644 --- a/resources/lib/WriteKodiVideoDB.py +++ b/resources/lib/WriteKodiVideoDB.py @@ -13,10 +13,12 @@ import sqlite3 import os from decimal import Decimal + from DownloadUtils import DownloadUtils from PlayUtils import PlayUtils from ReadKodiDB import ReadKodiDB from ReadEmbyDB import ReadEmbyDB +from TextureCache import TextureCache from API import API import Utils as utils @@ -26,6 +28,8 @@ from xml.dom import minidom import xml.etree.cElementTree as ET class WriteKodiVideoDB(): + + textureCache = TextureCache() def updatePlayCountFromKodi(self, id, type, playcount=0): #when user marks item watched from kodi interface update this in Emby @@ -772,6 +776,10 @@ class WriteKodiVideoDB(): if(url != imageUrl): utils.logMsg("ArtworkSync", "Updating Art Link for kodiId: " + str(kodiId) + " (" + url + ") -> (" + imageUrl + ")") cursor.execute("UPDATE art set url = ? WHERE media_id = ? AND media_type = ? AND type = ?", (imageUrl, kodiId, mediaType, imageType)) + + #cache fanart and poster in Kodi texture cache + if imageType == "fanart" or imageType == "poster": + self.textureCache.CacheTexture(imageUrl) def setKodiResumePoint(self, fileid, resume_seconds, total_seconds, cursor): @@ -990,8 +998,7 @@ class WriteKodiVideoDB(): else: #only movies have a country field return - - + def AddStudiosToMedia(self, id, studios, mediatype, cursor): if studios: @@ -1208,5 +1215,4 @@ class WriteKodiVideoDB(): #update the checksum in emby table cursor.execute("UPDATE emby SET checksum = ? WHERE emby_id = ?", (API().getChecksum(boxsetmovie),boxsetmovie["Id"])) - - + \ No newline at end of file diff --git a/resources/settings.xml b/resources/settings.xml index 635c5474..41a1ee6f 100644 --- a/resources/settings.xml +++ b/resources/settings.xml @@ -16,7 +16,8 @@ - + +