jellycon/resources/lib/cache_images.py
2022-03-09 22:51:38 +01:00

354 lines
13 KiB
Python

# coding=utf-8
# Gnu General Public License - see LICENSE.TXT
from __future__ import division, absolute_import, print_function, unicode_literals
from six.moves.urllib.parse import unquote
import requests
import base64
import sys
import threading
import time
import xbmcgui
import xbmcplugin
import xbmc
import xbmcaddon
from .jellyfin import api
from .lazylogger import LazyLogger
from .jsonrpc import JsonRpc, get_value
from .utils import translate_string, load_user_details
from .kodi_utils import HomeWindow
from .item_functions import get_art
log = LazyLogger(__name__)
class CacheArtwork(threading.Thread):
stop_all_activity = False
def __init__(self):
log.debug("CacheArtwork init")
self.stop_all_activity = False
super(CacheArtwork, self).__init__()
def stop_activity(self):
self.stop_all_activity = True
def run(self):
log.debug("CacheArtwork background thread started")
last_update = 0
home_window = HomeWindow()
settings = xbmcaddon.Addon()
latest_content_hash = "never"
check_interval = int(settings.getSetting('cacheImagesOnScreenSaver_interval'))
check_interval = check_interval * 60
monitor = xbmc.Monitor()
monitor.waitForAbort(5)
while not self.stop_all_activity and not monitor.abortRequested() and xbmc.getCondVisibility("System.ScreenSaverActive"):
content_hash = home_window.get_property("jellycon_widget_reload")
if (check_interval != 0 and (time.time() - last_update) > check_interval) or (latest_content_hash != content_hash):
log.debug("CacheArtwork background thread - triggered")
if monitor.waitForAbort(10):
break
if self.stop_all_activity or monitor.abortRequested():
break
self.cache_artwork_background()
last_update = time.time()
latest_content_hash = content_hash
monitor.waitForAbort(5)
log.debug("CacheArtwork background thread exited : stop_all_activity : {0}".format(self.stop_all_activity))
@staticmethod
def delete_cached_images(item_id):
log.debug("cache_delete_for_links")
progress = xbmcgui.DialogProgress()
progress.create(translate_string(30281))
progress.update(30, translate_string(30347))
item_image_url_part = "Items/%s/Images/" % item_id
item_image_url_part = item_image_url_part.replace("/", "%2f")
log.debug("texture ids: {0}".format(item_image_url_part))
# is the web server enabled
web_query = {"setting": "services.webserver"}
result = JsonRpc('Settings.GetSettingValue').execute(web_query)
xbmc_webserver_enabled = result['result']['value']
if not xbmc_webserver_enabled:
xbmcgui.Dialog().ok(translate_string(30294), translate_string(30295))
return
params = {"properties": ["url"]}
json_result = JsonRpc('Textures.GetTextures').execute(params)
textures = json_result.get("result", {}).get("textures", [])
log.debug("texture ids: {0}".format(textures))
progress.update(70, translate_string(30346))
delete_count = 0
for texture in textures:
texture_id = texture["textureid"]
texture_url = texture["url"]
if item_image_url_part in texture_url:
delete_count += 1
log.debug("removing texture id: {0}".format(texture_id))
params = {"textureid": int(texture_id)}
JsonRpc('Textures.RemoveTexture').execute(params)
del textures
progress.update(100, translate_string(30125))
progress.close()
xbmcgui.Dialog().ok(translate_string(30281), '{}: {}'.format(translate_string(30344), delete_count))
def cache_artwork_interactive(self):
log.debug("cache_artwork_interactive")
xbmcplugin.endOfDirectory(int(sys.argv[1]), cacheToDisc=False)
# is the web server enabled
web_query = {"setting": "services.webserver"}
result = JsonRpc('Settings.GetSettingValue').execute(web_query)
xbmc_webserver_enabled = result['result']['value']
if not xbmc_webserver_enabled:
xbmcgui.Dialog().ok(translate_string(30294), '{} - {}'.format(translate_string(30295), translate_string(30355)))
xbmc.executebuiltin('ActivateWindow(servicesettings)')
return
result_report = []
# ask questions
question_delete_unused = xbmcgui.Dialog().yesno(translate_string(30296), translate_string(30297))
question_cache_images = xbmcgui.Dialog().yesno(translate_string(30299), translate_string(30300))
delete_canceled = False
# now do work - delete unused
if question_delete_unused:
delete_pdialog = xbmcgui.DialogProgress()
delete_pdialog.create(translate_string(30298), "")
index = 0
params = {"properties": ["url"]}
json_result = JsonRpc('Textures.GetTextures').execute(params)
textures = json_result.get("result", {}).get("textures", [])
jellyfin_texture_urls = self.get_jellyfin_artwork(delete_pdialog)
log.debug("kodi textures: {0}".format(textures))
log.debug("jellyfin texture urls: {0}".format(jellyfin_texture_urls))
if jellyfin_texture_urls is not None:
unused_texture_ids = set()
for texture in textures:
url = texture.get("url")
url = unquote(url)
url = url.replace("image://", "")
url = url[0:-1]
if url.find("/") > -1 and url not in jellyfin_texture_urls or url.find("localhost:24276") > -1:
unused_texture_ids.add(texture["textureid"])
total = len(unused_texture_ids)
log.debug("unused texture ids: {0}".format(unused_texture_ids))
for texture_id in unused_texture_ids:
params = {"textureid": int(texture_id)}
JsonRpc('Textures.RemoveTexture').execute(params)
percentage = int((float(index) / float(total)) * 100)
message = "%s of %s" % (index, total)
delete_pdialog.update(percentage, message)
index += 1
if delete_pdialog.iscanceled():
delete_canceled = True
break
result_report.append(translate_string(30385) + str(len(textures)))
result_report.append(translate_string(30386) + str(len(unused_texture_ids)))
result_report.append(translate_string(30387) + str(index))
del textures
del jellyfin_texture_urls
del unused_texture_ids
delete_pdialog.close()
del delete_pdialog
if delete_canceled:
xbmc.sleep(2000)
# now do work - cache images
if question_cache_images:
cache_pdialog = xbmcgui.DialogProgress()
cache_pdialog.create(translate_string(30301), "")
cache_report = self.cache_artwork(cache_pdialog)
cache_pdialog.close()
del cache_pdialog
if cache_report:
result_report.extend(cache_report)
if len(result_report) > 0:
msg = "\r\n".join(result_report)
xbmcgui.Dialog().textviewer(translate_string(30125), msg, usemono=True)
def cache_artwork_background(self):
log.debug("cache_artwork_background")
dp = xbmcgui.DialogProgressBG()
dp.create(translate_string(30301), "")
result_text = None
try:
result_text = self.cache_artwork(dp)
except Exception as err:
log.error("Cache Images Failed : {0}".format(err))
dp.close()
del dp
if result_text is not None:
log.debug("Cache Images reuslt : {0}".format(" - ".join(result_text)))
def get_jellyfin_artwork(self, progress):
log.debug("get_jellyfin_artwork")
user_details = load_user_details()
user_id = user_details.get('user_id')
url = ""
url += "/Users/{}/Items".format(user_id)
url += "?Recursive=true"
url += "&EnableUserData=False"
url += "&Fields=BasicSyncInfo"
url += "&IncludeItemTypes=Movie,Series,Episode,BoxSet"
url += "&ImageTypeLimit=1"
url += "&format=json"
results = api.get(url)
if results is None:
results = []
if isinstance(results, dict):
results = results.get("Items")
settings = xbmcaddon.Addon()
server = settings.getSetting('server_address')
log.debug("Jellyfin Item Count Count: {0}".format(len(results)))
if self.stop_all_activity:
return None
progress.update(0, translate_string(30359))
texture_urls = set()
for item in results:
art = get_art(item, server)
for art_type in art:
texture_urls.add(art[art_type])
return texture_urls
def cache_artwork(self, progress):
log.debug("cache_artwork")
# is the web server enabled
if not get_value("services.webserver"):
log.error("Kodi web server not enabled, can not cache images")
return
# get the port
xbmc_port = get_value("services.webserverport")
log.debug("xbmc_port: {0}".format(xbmc_port))
# get the user
xbmc_username = get_value("services.webserverusername")
log.debug("xbmc_username: {0}".format(xbmc_username))
# get the password
xbmc_password = get_value("services.webserverpassword")
progress.update(0, translate_string(30356))
params = {"properties": ["url"]}
json_result = JsonRpc('Textures.GetTextures').execute(params)
textures = json_result.get("result", {}).get("textures", [])
log.debug("Textures.GetTextures Count: {0}".format(len(textures)))
if self.stop_all_activity:
return
progress.update(0, translate_string(30357))
texture_urls = set()
for texture in textures:
url = texture.get("url")
url = unquote(url)
url = url.replace("image://", "")
url = url[0:-1]
texture_urls.add(url)
del textures
del json_result
log.debug("texture_urls Count: {0}".format(len(texture_urls)))
if self.stop_all_activity:
return
progress.update(0, translate_string(30358))
jellyfin_texture_urls = self.get_jellyfin_artwork(progress)
if jellyfin_texture_urls is None:
return
missing_texture_urls = set()
for image_url in jellyfin_texture_urls:
if image_url not in texture_urls and not image_url.endswith("&Tag=") and len(image_url) > 0:
missing_texture_urls.add(image_url)
if self.stop_all_activity:
return
log.debug("texture_urls: {0}".format(texture_urls))
log.debug("missing_texture_urls: {0}".format(missing_texture_urls))
log.debug("Number of existing textures: {0}".format(len(texture_urls)))
log.debug("Number of missing textures: {0}".format(len(missing_texture_urls)))
kodi_http_server = "localhost:" + str(xbmc_port)
headers = {}
if xbmc_password:
auth = "%s:%s" % (xbmc_username, xbmc_password)
headers = {'Authorization': 'Basic %s' % base64.b64encode(auth)}
total = len(missing_texture_urls)
count_done = 0
for index, get_url in enumerate(missing_texture_urls, 1):
kodi_texture_url = "/image/image://{0}".format(get_url)
log.debug("kodi_texture_url: {0}".format(kodi_texture_url))
percentage = int((float(index) / float(total)) * 100)
message = "%s of %s" % (index, total)
progress.update(percentage, message)
cache_url = "http://%s%s" % (kodi_http_server, kodi_texture_url)
data = requests.get(cache_url, timeout=20, headers=headers)
if data.status_code == 200:
count_done += 1
log.debug("Get Image Result: {0}".format(data.status_code))
if isinstance(progress, xbmcgui.DialogProgress) and progress.iscanceled():
break
if self.stop_all_activity:
break
result_report = []
result_report.append(translate_string(30302) + str(len(texture_urls)))
result_report.append(translate_string(30303) + str(len(missing_texture_urls)))
result_report.append(translate_string(30304) + str(count_done))
return result_report