Files
jellycon/resources/lib/image_server.py
2022-02-27 22:15:54 -05:00

208 lines
5.6 KiB
Python

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 .loghandler import LazyLogger
from .datamanager import DataManager
from .item_functions import get_art
pil_loaded = False
try:
from PIL import ImageFilter, Image, ImageOps
pil_loaded = True
except Exception as err:
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"
data_manager = DataManager()
result = data_manager.get_content(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 = xbmc.translatePath("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")