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

View File

@ -5,12 +5,12 @@ __license__ = 'GPL v3'
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>' __copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
import re, os, posixpath, json import re, os, posixpath
import cherrypy import cherrypy
from calibre import fit_image, guess_type 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.caches import SortKeyGenerator
from calibre.library.save_to_disk import find_plugboard from calibre.library.save_to_disk import find_plugboard
from calibre.ebooks.metadata import authors_to_string 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) thumbnail as generate_thumbnail)
from calibre.utils.filenames import ascii_filename from calibre.utils.filenames import ascii_filename
from calibre.ebooks.metadata.opf2 import metadata_to_opf from calibre.ebooks.metadata.opf2 import metadata_to_opf
from calibre.utils.config import prefs
plugboard_content_server_value = 'content_server' plugboard_content_server_value = 'content_server'
plugboard_content_server_formats = ['epub'] plugboard_content_server_formats = ['epub']
@ -94,7 +93,7 @@ class ContentServer(object):
if what == 'opf': if what == 'opf':
return self.get_metadata_as_opf(id) return self.get_metadata_as_opf(id)
if what == 'json': if what == 'json':
return self.get_metadata_as_json(id) raise cherrypy.InternalRedirect('/ajax/book/%d'%id)
return self.get_format(id, what) return self.get_format(id, what)
def static(self, name): def static(self, name):
@ -196,51 +195,6 @@ class ContentServer(object):
return data 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): def get_format(self, id, format):
format = format.upper() format = format.upper()