from papiezator.models import Pope, PopeImage, PerfectPope, DECIMAL_PLACES from PIL import Image from io import BytesIO from django.core.exceptions import ObjectDoesNotExist from random import choice from django.http import HttpResponse from papiezator.papiezator_settings import ( REDIS_TTL, SAGE_REDIS, POPE_SPAN, POPE_CHOICE_RANGE ) try: from redis import Redis from redis.exceptions import ConnectionError as RedisConnectionError redis = Redis() except ImportError: redis = None def unpopable(width, height): if width == 0 or height == 0: return True if (width+height) >= 9001: return True return False #======== your friendly decorators :3 ====================================== def redis_me(func): def inner(*args, **kwargs): import ipdb; ipdb.set_trace() if not redis or SAGE_REDIS: return func(*args, **kwargs) # FIXME: perhaps some better key value? key = (func.__name__, args) try: image = redis.get(key) if not image: image = func(*args, **kwargs) redis.set(key, image) redis.expire(key, REDIS_TTL) return image except RedisConnectionError: return func(*args, **kwargs) return inner def habemus_papam(func): """Your friendly, pointless decorator ;3 """ def inner(aspect_ratio, pope): pp = PerfectPope.objects.filter(aspect_ratio=aspect_ratio, pope=pope) if pp: return pp[0].image PopeImage = func(aspect_ratio, pope) pp = PerfectPope(aspect_ratio=aspect_ratio, image=PopeImage, pope=pope) pp.save() return PopeImage return inner def http_return_image(func): def inner(*args, **kwargs): image = func(*args, **kwargs) if image: return HttpResponse(image, content_type="image/jpeg") else: return HttpResponse("Jan Paweł II spadał z rowerka") return inner # ============================================================================= @redis_me def get_pope(width, height, pope_id): width, height = int(width), int(height) if not unpopable(width, height): pope = pope_or_death(Pope, id=pope_id) if pope: aspect_ratio = round(width/height, DECIMAL_PLACES) pope_image = select_best_pope(aspect_ratio, pope) if pope_image: return read_pope(width, height, pope_image) return None @habemus_papam def select_best_pope(aspect_ratio, pope, random=True): """ (float, Pope) -> PopeImage """ # popes below and above this ratio popes = [] popes.extend( PopeImage.objects.filter( aspect_ratio__lte=aspect_ratio, pope=pope).order_by('-aspect_ratio')[0:POPE_SPAN] ) popes.extend( PopeImage.objects.filter( aspect_ratio__gte=aspect_ratio, pope=pope).order_by('aspect_ratio')[0:POPE_SPAN] ) if popes: p = sorted( popes, key=lambda x: abs(aspect_ratio - x.aspect_ratio) ) if random: return choice(p[:POPE_CHOICE_RANGE]) else: return p[0] else: return None def read_pope(width, height, pope_image): """ (int, int, PopeImage) -> bytes get pope for display """ im = Image.open(pope_image.path) im = im.resize((width, height)) f = BytesIO() # FIXME: ceriously. im.save(f, "jpeg") f.seek(0) return f.read() def parse_pope(path): im = Image.open(path) width, height = im.size aspect_ratio = round(width/height, DECIMAL_PLACES) return PopeImage( path=path, width=width, height=height, aspect_ratio=aspect_ratio ) def pope_or_death(p, **kwargs): try: x = p.objects.get(**kwargs) except ObjectDoesNotExist: x = None return x