This commit is contained in:
Kovid Goyal 2011-08-28 15:22:20 -06:00
parent 7ed0c98bab
commit 39798e6a5c
3 changed files with 120 additions and 52 deletions

View File

@ -0,0 +1,114 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
from __future__ import (unicode_literals, division, absolute_import,
print_function)
__license__ = 'GPL v3'
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import json
from functools import wraps
import cherrypy
from calibre.utils.date import isoformat
from calibre.utils.config import prefs
from calibre.ebooks.metadata.book.json_codec import JsonCodec
class Endpoint(object): # {{{
'Manage mime-type json serialization, etc.'
def __init__(self, mimetype='application/json; charset=utf-8',
set_last_modified=True):
self.mimetype = mimetype
self.set_last_modified = set_last_modified
def __call__(eself, func):
@wraps(func)
def wrapper(self, *args, **kwargs):
# Remove AJAX caching disabling jquery workaround arg
# This arg is put into AJAX queries by jQuery to prevent
# caching in the browser. We dont want it passed to the wrapped
# function
kwargs.pop('_', None)
ans = func(self, *args, **kwargs)
cherrypy.response.headers['Content-Type'] = eself.mimetype
if eself.set_last_modified:
updated = self.db.last_modified()
cherrypy.response.headers['Last-Modified'] = \
self.last_modified(max(updated, self.build_time))
if 'application/json' in eself.mimetype:
ans = json.dumps(ans, indent=2,
ensure_ascii=False).encode('utf-8')
return ans
return wrapper
# }}}
class AjaxServer(object):
def __init__(self):
self.ajax_json_codec = JsonCodec()
def add_routes(self, connect):
base_href = '/ajax'
connect('ajax_book', base_href+'/book/{book_id}', self.ajax_book)
# Get book metadata {{{
@Endpoint()
def ajax_book(self, book_id):
cherrypy.response.headers['Content-Type'] = \
'application/json; charset=utf-8'
try:
book_id = int(book_id)
mi = self.db.get_metadata(book_id, index_is_id=True)
except:
raise cherrypy.HTTPError(404, 'No book with id: %r'%book_id)
try:
mi.rating = mi.rating/2.
except:
mi.rating = 0.0
cherrypy.response.timeout = 3600
cherrypy.response.headers['Last-Modified'] = \
self.last_modified(mi.last_modified)
data = self.ajax_json_codec.encode_book_metadata(mi)
for x in ('publication_type', 'size', 'db_id', 'lpath', 'mime',
'rights', 'book_producer'):
data.pop(x, None)
def absurl(url):
return self.opts.url_prefix + url
data['cover'] = absurl(u'/get/cover/%d'%book_id)
data['thumbnail'] = absurl(u'/get/thumb/%d'%book_id)
mi.format_metadata = {k:dict(v) for k, v in
mi.format_metadata.iteritems()}
for v in mi.format_metadata.itervalues():
mtime = v.get('mtime', None)
if mtime is not None:
v['mtime'] = isoformat(mtime, as_utc=True)
data['format_metadata'] = mi.format_metadata
fmts = set(x.lower() for x in mi.format_metadata.iterkeys())
pf = prefs['output_format'].lower()
other_fmts = list(fmts)
try:
fmt = pf if pf in fmts else other_fmts[0]
except:
fmt = None
if fmts and fmt:
other_fmts = [x for x in fmts if x != fmt]
data['formats'] = sorted(fmts)
if fmt:
data['main_format'] = {fmt: absurl(u'/get/%s/%d'%(fmt, book_id))}
else:
data['main_format'] = None
data['other_formats'] = {fmt: absurl(u'/get/%s/%d'%(fmt, book_id)) for fmt
in other_fmts}
return data
# }}}

View File

@ -24,9 +24,9 @@ from calibre.library.server.xml import XMLServer
from calibre.library.server.opds import OPDSServer
from calibre.library.server.cache import Cache
from calibre.library.server.browse import BrowseServer
from calibre.library.server.ajax import AjaxServer
from calibre.utils.search_query_parser import saved_searches
from calibre import prints
from calibre.ebooks.metadata.book.json_codec import JsonCodec
class DispatchController(object): # {{{
@ -100,7 +100,7 @@ cherrypy.engine.bonjour = BonJour(cherrypy.engine)
# }}}
class LibraryServer(ContentServer, MobileServer, XMLServer, OPDSServer, Cache,
BrowseServer):
BrowseServer, AjaxServer):
server_name = __appname__ + '/' + __version__
@ -164,11 +164,11 @@ class LibraryServer(ContentServer, MobileServer, XMLServer, OPDSServer, Cache,
self.__dispatcher__ = DispatchController(self.opts.url_prefix, wsgi)
for x in self.__class__.__bases__:
if hasattr(x, 'add_routes'):
x.__init__(self)
x.add_routes(self, self.__dispatcher__)
root_conf = self.config.get('/', {})
root_conf['request.dispatch'] = self.__dispatcher__.dispatcher
self.config['/'] = root_conf
self.json_codec = JsonCodec()
def set_database(self, db):
self.db = db

View File

@ -5,12 +5,12 @@ __license__ = 'GPL v3'
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import re, os, posixpath, json
import re, os, posixpath
import cherrypy
from calibre import fit_image, guess_type
from calibre.utils.date import fromtimestamp, isoformat
from calibre.utils.date import fromtimestamp
from calibre.library.caches import SortKeyGenerator
from calibre.library.save_to_disk import find_plugboard
from calibre.ebooks.metadata import authors_to_string
@ -18,7 +18,6 @@ from calibre.utils.magick.draw import (save_cover_data_to, Image,
thumbnail as generate_thumbnail)
from calibre.utils.filenames import ascii_filename
from calibre.ebooks.metadata.opf2 import metadata_to_opf
from calibre.utils.config import prefs
plugboard_content_server_value = 'content_server'
plugboard_content_server_formats = ['epub']
@ -94,7 +93,7 @@ class ContentServer(object):
if what == 'opf':
return self.get_metadata_as_opf(id)
if what == 'json':
return self.get_metadata_as_json(id)
raise cherrypy.InternalRedirect('/ajax/book/%d'%id)
return self.get_format(id, what)
def static(self, name):
@ -196,51 +195,6 @@ class ContentServer(object):
return data
def get_metadata_as_json(self, id_):
cherrypy.response.headers['Content-Type'] = \
'application/json; charset=utf-8'
mi = self.db.get_metadata(id_, index_is_id=True)
try:
mi.rating = mi.rating/2.
except:
mi.rating = 0.0
cherrypy.response.timeout = 3600
cherrypy.response.headers['Last-Modified'] = \
self.last_modified(mi.last_modified)
data = self.json_codec.encode_book_metadata(mi)
for x in ('publication_type', 'size', 'db_id', 'lpath', 'mime',
'rights', 'book_producer'):
data.pop(x, None)
def absurl(url):
return self.opts.url_prefix + url
data['cover'] = absurl(u'/get/cover/%d'%id_)
data['thumbnail'] = absurl(u'/get/thumb/%d'%id_)
for v in mi.format_metadata.itervalues():
mtime = v.get('mtime', None)
if mtime is not None:
v['mtime'] = isoformat(mtime, as_utc=True)
data['format_metadata'] = mi.format_metadata
fmts = set(x.lower() for x in mi.format_metadata.iterkeys())
pf = prefs['output_format'].lower()
other_fmts = list(fmts)
try:
fmt = pf if pf in fmts else other_fmts[0]
except:
fmt = None
if fmts and fmt:
other_fmts = [x for x in fmts if x != fmt]
data['formats'] = sorted(fmts)
if fmt:
data['main_format'] = {fmt: absurl(u'/get/%s/%d'%(fmt, id_))}
else:
data['main_format'] = None
data['other_formats'] = {fmt: absurl(u'/get/%s/%d'%(fmt, id_)) for fmt
in other_fmts}
return json.dumps(data, indent=2, ensure_ascii=False).encode('utf-8')
def get_format(self, id, format):
format = format.upper()