openmedialibrary/oml/item/icons.py

176 lines
4.6 KiB
Python
Raw Normal View History

2014-05-04 17:26:43 +00:00
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
2014-05-19 21:39:52 +00:00
from __future__ import division, with_statement
2014-05-04 17:26:43 +00:00
import sqlite3
from StringIO import StringIO
2014-05-19 21:39:52 +00:00
import Image
import tornado.ioloop
import tornado.web
import tornado.gen
import tornado.concurrent
from oxtornado import run_async
from utils import resize_image
2014-05-04 17:26:43 +00:00
2014-05-21 00:02:21 +00:00
from settings import icons_db_path
2014-05-04 17:26:43 +00:00
2014-05-21 00:02:21 +00:00
import logging
logger = logging.getLogger('oml.item.icons')
class Icons(dict):
2014-05-04 17:26:43 +00:00
def __init__(self, db):
self._db = db
2014-05-17 09:24:17 +00:00
self.create()
2014-05-04 17:26:43 +00:00
def connect(self):
2014-05-17 09:24:17 +00:00
conn = sqlite3.connect(self._db, timeout=10)
return conn
2014-05-04 17:26:43 +00:00
def create(self):
2014-05-17 09:24:17 +00:00
conn = self.connect()
c = conn.cursor()
2014-05-21 00:02:21 +00:00
c.execute(u'CREATE TABLE IF NOT EXISTS icon (id varchar(64) unique, data blob)')
2014-05-04 17:26:43 +00:00
c.execute(u'CREATE TABLE IF NOT EXISTS setting (key varchar(256) unique, value text)')
if int(self.get_setting(c, 'version', 0)) < 1:
self.set_setting(c, 'version', 1)
def get_setting(self, c, key, default=None):
c.execute(u'SELECT value FROM setting WHERE key = ?', (key, ))
for row in c:
return row[0]
return default
def set_setting(self, c, key, value):
c.execute(u'INSERT OR REPLACE INTO setting values (?, ?)', (key, str(value)))
def black(self):
img = Image.new('RGB', (80, 128))
o = StringIO()
img.save(o, format='jpeg')
data = o.getvalue()
o.close()
return data
def __getitem__(self, id, default=None):
2014-05-21 00:02:21 +00:00
sql = u'SELECT data FROM icon WHERE id=?'
2014-05-17 09:24:17 +00:00
conn = self.connect()
c = conn.cursor()
2014-05-04 17:26:43 +00:00
c.execute(sql, (id, ))
data = default
for row in c:
data = row[0]
break
c.close()
2014-05-17 09:24:17 +00:00
conn.close()
2014-05-04 17:26:43 +00:00
return data
def __setitem__(self, id, data):
2014-05-21 00:02:21 +00:00
sql = u'INSERT OR REPLACE INTO icon values (?, ?)'
2014-05-17 09:24:17 +00:00
conn = self.connect()
c = conn.cursor()
2014-05-04 17:26:43 +00:00
data = sqlite3.Binary(data)
c.execute(sql, (id, data))
2014-05-17 09:24:17 +00:00
conn.commit()
2014-05-04 17:26:43 +00:00
c.close()
2014-05-17 09:24:17 +00:00
conn.close()
2014-05-04 17:26:43 +00:00
def __delitem__(self, id):
2014-05-21 00:02:21 +00:00
sql = u'DELETE FROM icon WHERE id = ?'
2014-05-17 09:24:17 +00:00
conn = self.connect()
c = conn.cursor()
2014-05-04 17:26:43 +00:00
c.execute(sql, (id, ))
2014-05-17 09:24:17 +00:00
conn.commit()
2014-05-04 17:26:43 +00:00
c.close()
2014-05-17 09:24:17 +00:00
conn.close()
2014-05-04 17:26:43 +00:00
2014-05-21 00:02:21 +00:00
icons = Icons(icons_db_path)
2014-05-19 21:39:52 +00:00
@run_async
2014-05-21 00:02:21 +00:00
def get_icon(app, id, type_, size, callback):
2014-05-26 10:11:13 +00:00
if size:
skey = '%s:%s:%s' % (type_, id, size)
data = icons[skey]
if data:
callback(str(data))
return
key = '%s:%s' % (type_, id)
if not icons[key]:
type_ = 'preview' if type_ == 'cover' else 'cover'
if size:
skey = '%s:%s:%s' % (type_, id, size)
data = None
if size:
data = icons[skey]
if data:
size = None
if not data:
data = icons[key]
if not data:
data = icons.black()
size = None
if size:
data = icons[skey] = resize_image(data, size=size)
data = str(data) or ''
callback(data)
@run_async
def get_icon_app(app, id, type_, size, callback):
2014-05-19 21:39:52 +00:00
with app.app_context():
from item.models import Item
item = Item.get(id)
if not item:
callback('')
2014-05-19 22:49:04 +00:00
else:
2014-05-21 00:02:21 +00:00
if type_ == 'cover' and not item.meta.get('cover'):
type_ = 'preview'
if type_ == 'preview' and not item.files.count():
type_ = 'cover'
if size:
skey = '%s:%s:%s' % (type_, id, size)
key = '%s:%s' % (type_, id)
2014-05-19 22:49:04 +00:00
data = None
if size:
2014-05-21 00:02:21 +00:00
data = icons[skey]
2014-05-19 22:49:04 +00:00
if data:
size = None
if not data:
2014-05-21 00:02:21 +00:00
data = icons[key]
2014-05-19 21:39:52 +00:00
if not data:
2014-05-21 00:02:21 +00:00
data = icons.black()
size = None
2014-05-19 22:49:04 +00:00
if size:
2014-05-21 00:02:21 +00:00
data = icons[skey] = resize_image(data, size=size)
data = str(data) or ''
2014-05-19 22:49:04 +00:00
callback(data)
2014-05-19 21:39:52 +00:00
2014-05-21 00:02:21 +00:00
class IconHandler(tornado.web.RequestHandler):
2014-05-19 21:39:52 +00:00
def initialize(self, app):
self._app = app
@tornado.web.asynchronous
@tornado.gen.coroutine
2014-05-21 00:02:21 +00:00
def get(self, id, type_, size=None):
size = int(size) if size else None
if type_ not in ('cover', 'preview'):
2014-05-25 20:32:00 +00:00
self.set_status(404)
self.finish()
2014-05-21 00:02:21 +00:00
return
self.set_header('Content-Type', 'image/jpeg')
response = yield tornado.gen.Task(get_icon, self._app, id, type_, size)
if not response:
2014-05-25 20:32:00 +00:00
self.set_status(404)
self.finish()
2014-05-21 00:02:21 +00:00
return
if self._finished:
return
self.write(response)