from __future__ import division, absolute_import, print_function, unicode_literals import xbmcvfs import xbmc import xbmcaddon import base64 import re from random import shuffle from six.moves.BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer from six.moves.urllib.parse import urlparse from six import ensure_text import threading import requests import io from .jellyfin import api from .lazylogger import LazyLogger from .item_functions import get_art from .utils import translate_path pil_loaded = False try: from PIL import Image, ImageOps pil_loaded = True except ImportError: pil_loaded = False PORT_NUMBER = 24276 log = LazyLogger(__name__) def get_image_links(url): settings = xbmcaddon.Addon() server = settings.getSetting('server_address') if server is None: return [] url = re.sub("(?i)EnableUserData=[a-z]+", "EnableUserData=False", url) url = re.sub("(?i)EnableImageTypes=[,a-z]+", "EnableImageTypes=Primary", url) url = url.replace("{field_filters}", "BasicSyncInfo") url = re.sub("(?i)Fields=[,a-z]+", "Fields=BasicSyncInfo", url) if not re.search('enableimagetypes=', url, re.IGNORECASE): url += "&EnableImageTypes=Primary" if not re.search('fields=', url, re.IGNORECASE): url += "&Fields=BasicSyncInfo" if not re.search('EnableUserData=', url, re.IGNORECASE): url += "&EnableUserData=False" result = api.get(url) items = result.get("Items") if not items: return [] art_urls = [] for iteem in items: art = get_art(item=iteem, server=server) art_urls.append(art) shuffle(art_urls) return art_urls def build_image(path): log.debug("build_image()") log.debug("Request Path : {0}".format(path)) request_path = path[1:] if request_path == "favicon.ico": return [] decoded_url = ensure_text(base64.b64decode(request_path)) log.debug("decoded_url : {0}".format(decoded_url)) image_urls = get_image_links(decoded_url) width, height = 500, 750 collage = Image.new('RGB', (width, height), (5, 5, 5)) cols = 2 rows = 2 thumbnail_width = int(width / cols) thumbnail_height = int(height / rows) size = (thumbnail_width, thumbnail_height) image_count = 0 for art in image_urls: thumb_url = art.get("thumb") if thumb_url: url_bits = urlparse(thumb_url.strip()) host_name = url_bits.hostname port = url_bits.port url_path = url_bits.path url_query = url_bits.query server = "%s:%s" % (host_name, port) url_full_path = url_path + "?" + url_query log.debug("Loading image from : {0} {1} {2}".format(image_count, server, url_full_path)) try: image_response = requests.get(thumb_url) image_data = image_response.content loaded_image = Image.open(io.BytesIO(image_data)) image = ImageOps.fit(loaded_image, size, method=Image.ANTIALIAS, bleed=0.0, centering=(0.5, 0.5)) x = int(image_count % cols) * thumbnail_width y = int(image_count/cols) * thumbnail_height collage.paste(image, (x, y)) del loaded_image del image del image_data except Exception as con_err: log.debug("Error loading image : {0}".format(con_err)) image_count += 1 if image_count == cols * rows: break del image_urls img_byte_arr = io.BytesIO() collage.save(img_byte_arr, format='JPEG') image_bytes = img_byte_arr.getvalue() return image_bytes class HttpImageHandler(BaseHTTPRequestHandler): def log_message(self, format, *args): log_line = format % args log.debug(log_line) return def do_GET(self): log.debug("HttpImageHandler:do_GET()") self.serve_image() return def do_HEAD(self): log.debug("HttpImageHandler:do_HEAD()") self.send_response(200) self.end_headers() return def serve_image(self): if pil_loaded: image_bytes = build_image(self.path) self.send_response(200) self.send_header('Content-type', 'image/jpeg') self.send_header('Content-Length', str(len(image_bytes))) self.end_headers() self.wfile.write(image_bytes) else: image_path = translate_path("special://home/addons/plugin.video.jellycon/icon.png").decode('utf-8') self.send_response(200) self.send_header('Content-type', 'image/png') modified = xbmcvfs.Stat(image_path).st_mtime() self.send_header('Last-Modified', "%s" % modified) image = xbmcvfs.File(image_path) size = image.size() self.send_header('Content-Length', str(size)) self.end_headers() self.wfile.write(image.readBytes()) image.close() del image class HttpImageServerThread(threading.Thread): def __init__(self): threading.Thread.__init__(self) self.keep_running = True def stop(self): log.debug("HttpImageServerThread:stop called") self.keep_running = False self.server.shutdown() def run(self): log.debug("HttpImageServerThread:started") self.server = HTTPServer(('', PORT_NUMBER), HttpImageHandler) while self.keep_running: self.server.serve_forever() xbmc.sleep(1000) log.debug("HttpImageServerThread:exiting")