diff --git a/plexpy/helpers.py b/plexpy/helpers.py index c028284e..0651c955 100644 --- a/plexpy/helpers.py +++ b/plexpy/helpers.py @@ -17,6 +17,8 @@ import base64 import datetime import fnmatch from functools import wraps +import hashlib +import imghdr from IPy import IP import json import math @@ -563,4 +565,38 @@ def uploadToImgur(imgPath, imgTitle=''): except (urllib2.HTTPError, urllib2.URLError) as e: logger.warn(u"PlexPy Helpers :: Unable to upload image to Imgur: %s" % e) - return img_url \ No newline at end of file + return img_url + +def cache_image(url, image=None): + """ + Saves an image to the cache directory. + If no image is provided, tries to return the image from the cach directory. + """ + from plexpy import logger + + # Create image directory if it doesn't exist + imgdir = os.path.join(plexpy.CONFIG.CACHE_DIR, 'images/') + if not os.path.exists(imgdir): + logger.debug(u"PlexPy Helpers :: Creating image cache directory at %s" % imgdir) + os.makedirs(imgdir) + + # Create a hash of the path to use as filename + imghash = hashlib.md5(url).hexdigest() + imagefile = os.path.join(imgdir, imghash) + + # If an image was provided, save it to the cache directory + if image: + try: + with open(imagefile, 'wb') as cache_file: + cache_file.write(image) + except IOError as e: + logger.error(u"PlexPy Helpers :: Failed to cache image %s: %s" % (imagefile, e)) + + # Try to return the image from the cache directory + if os.path.isfile(imagefile): + imagetype = 'image/' + imghdr.what(os.path.abspath(imagefile)) + else: + imagefile = None + imagetype = 'image/jpeg' + + return imagefile, imagetype \ No newline at end of file diff --git a/plexpy/pmsconnect.py b/plexpy/pmsconnect.py index cbe2118b..5d42c15f 100644 --- a/plexpy/pmsconnect.py +++ b/plexpy/pmsconnect.py @@ -1886,7 +1886,7 @@ class PmsConnect(object): return labels_list - def get_image(self, img=None, width=None, height=None): + def get_image(self, img=None, width=None, height=None, fallback=None): """ Return image data as array. Array contains the image content type and image binary @@ -1896,21 +1896,51 @@ class PmsConnect(object): height { the image height } Output: array """ - if img: + if not img: + logger.error(u"PlexPy Pmsconnect :: Image proxy queried but no input received.") + return None + + # Remove the timestamp from PMS image uri + image_uri = img.rsplit('/', 1)[0] + + # Try to retrieve the image from cache if it isn't a bif index. + if not 'indexes' in image_uri: + image_path, content_type = helpers.cache_image(image_uri) + + if image_path and content_type: + return [open(image_path, 'rb'), content_type] + + try: if width.isdigit() and height.isdigit(): uri = '/photo/:/transcode?url=http://127.0.0.1:32400' + img + '&width=' + width + '&height=' + height else: - uri = '/photo/:/transcode?url=http://127.0.0.1:32400' + img + logger.error(u"PlexPy Pmsconnect :: Image proxy queried but no width or height specified.") + raise Exception request, content_type = self.request_handler.make_request(uri=uri, proto=self.protocol, request_type='GET', return_type=True) + # Save the image to cache if it isn't a bif index. + if not 'indexes' in image_uri: + helpers.cache_image(image_uri, request) return [request, content_type] - else: - logger.error(u"PlexPy Pmsconnect :: Image proxy queries but no input received.") - return None + + except Exception as e: + if fallback: + logger.debug(u"PlexPy Pmsconnect :: Trying fallback %s image." % fallback) + try: + if fallback == 'poster': + return [open(common.DEFAULT_POSTER_THUMB, 'rb'), 'image/png'] + elif fallback == 'cover': + return [open(common.DEFAULT_COVER_THUMB, 'rb'), 'image/png'] + elif fallback == 'art': + return [open(common.DEFAULT_ART, 'rb'), 'image/png'] + except IOError as e: + logger.error(u"PlexPy Pmsconnect :: Unable to read fallback %s image: %s" % (fallback, e)) + + return None def get_search_results(self, query=''): """ diff --git a/plexpy/webserve.py b/plexpy/webserve.py index 50a1a926..fb51f102 100644 --- a/plexpy/webserve.py +++ b/plexpy/webserve.py @@ -1887,38 +1887,14 @@ class WebInterface(object): @cherrypy.expose @requireAuth() def pms_image_proxy(self, img='', width='0', height='0', fallback=None, **kwargs): - try: - pms_connect = pmsconnect.PmsConnect() - result = pms_connect.get_image(img, width, height) + + pms_connect = pmsconnect.PmsConnect() + result = pms_connect.get_image(img, width, height, fallback) + + if result: cherrypy.response.headers['Content-type'] = result[1] return result[0] - except: - logger.warn(u"Image proxy queried but errors occurred.") - if fallback == 'poster': - logger.info(u"Trying fallback image...") - try: - fallback_image = open(self.interface_dir + common.DEFAULT_POSTER_THUMB, 'rb') - cherrypy.response.headers['Content-type'] = 'image/png' - return fallback_image - except IOError, e: - logger.error(u"Unable to read fallback %s image: %s" % (fallback, e)) - elif fallback == 'cover': - logger.info(u"Trying fallback image...") - try: - fallback_image = open(self.interface_dir + common.DEFAULT_COVER_THUMB, 'rb') - cherrypy.response.headers['Content-type'] = 'image/png' - return fallback_image - except IOError, e: - logger.error(u"Unable to read fallback %s image: %s" % (fallback, e)) - elif fallback == 'art': - logger.info(u"Trying fallback image...") - try: - fallback_image = open(self.interface_dir + common.DEFAULT_ART, 'rb') - cherrypy.response.headers['Content-type'] = 'image/png' - return fallback_image - except IOError, e: - logger.error(u"Unable to read fallback %s image: %s" % (fallback, e)) - + else: return None @cherrypy.expose