diff --git a/src/calibre/ebooks/covers.py b/src/calibre/ebooks/covers.py
index d7df5c61cb..7fdb122674 100644
--- a/src/calibre/ebooks/covers.py
+++ b/src/calibre/ebooks/covers.py
@@ -53,6 +53,18 @@ authors = re(authors, ' & ', '
');
re(authors, '&&', '&')
'''
Prefs = namedtuple('Prefs', ' '.join(sorted(cprefs.defaults)))
+
+_use_roman = None
+def get_use_roman():
+ global _use_roman
+ if _use_roman is None:
+ return config['use_roman_numerals_for_series_number']
+ return _use_roman
+
+def set_use_roman(val):
+ global _use_roman
+ _use_roman = bool(val)
+
# }}}
# Draw text {{{
@@ -255,7 +267,7 @@ def preserve_fields(obj, fields):
def format_text(mi, prefs):
with preserve_fields(mi, 'authors formatted_series_index'):
mi.authors = [a for a in mi.authors if a != _('Unknown')]
- mi.formatted_series_index = fmt_sidx(mi.series_index or 0, use_roman=config['use_roman_numerals_for_series_number'])
+ mi.formatted_series_index = fmt_sidx(mi.series_index or 0, use_roman=get_use_roman())
return tuple(format_fields(mi, prefs))
# }}}
diff --git a/src/calibre/srv/code.py b/src/calibre/srv/code.py
index 7352e80ad2..2720224d78 100644
--- a/src/calibre/srv/code.py
+++ b/src/calibre/srv/code.py
@@ -4,20 +4,19 @@
from __future__ import (unicode_literals, division, absolute_import,
print_function)
-import re, hashlib, random, os
+import re, hashlib, random
from functools import partial
from threading import Lock
from json import load as load_json_file, dumps as json_dumps
from calibre import prepare_string_for_xml, as_unicode
-from calibre.constants import config_dir
from calibre.customize.ui import available_input_formats
from calibre.db.view import sanitize_sort_field_name
from calibre.srv.ajax import search_result
from calibre.srv.errors import HTTPNotFound, HTTPBadRequest
from calibre.srv.metadata import book_as_json, categories_as_json, icon_map
from calibre.srv.routes import endpoint, json
-from calibre.srv.utils import get_library_data
+from calibre.srv.utils import get_library_data, get_use_roman
from calibre.utils.config import prefs, tweaks
from calibre.utils.icu import sort_key
from calibre.utils.search_query_parser import ParseException
@@ -82,20 +81,6 @@ def get_basic_query_data(ctx, rd):
sorts, orders = ['timestamp'], ['desc']
return library_id, db, sorts, orders
-_use_roman = None
-
-def get_use_roman():
- global _use_roman
- if _use_roman is None:
- try:
- with lopen(os.path.join(config_dir, 'gui.py'), 'rb') as f:
- raw = f.read()
- except EnvironmentError:
- _use_roman = False
- else:
- m = re.search(br'use_roman_numerals_for_series_number\s*=\s*(True|False)', raw)
- _use_roman = m is not None and m.group(1) == b'True'
- return _use_roman
DEFAULT_NUMBER_OF_BOOKS = 50
diff --git a/src/calibre/srv/content.py b/src/calibre/srv/content.py
index fa4641f562..838f657cca 100644
--- a/src/calibre/srv/content.py
+++ b/src/calibre/srv/content.py
@@ -11,6 +11,7 @@ from binascii import hexlify
from io import BytesIO
from threading import Lock
from future_builtins import map
+from functools import partial
from calibre import fit_image
from calibre.constants import config_dir, iswindows
@@ -21,12 +22,13 @@ from calibre.ebooks.metadata.opf2 import metadata_to_opf
from calibre.library.save_to_disk import find_plugboard
from calibre.srv.errors import HTTPNotFound
from calibre.srv.routes import endpoint, json
-from calibre.srv.utils import http_date, get_db
+from calibre.srv.utils import http_date, get_db, get_use_roman
from calibre.utils.config_base import tweaks
from calibre.utils.date import timestampfromdt
from calibre.utils.img import scale_image, image_from_data
from calibre.utils.filenames import ascii_filename, atomic_rename
from calibre.utils.shared_file import share_open
+from calibre.utils.ipc.simple_worker import fork_job, WorkerError
plugboard_content_server_value = 'content_server'
plugboard_content_server_formats = ['epub', 'mobi', 'azw3']
@@ -94,10 +96,45 @@ def create_file_copy(ctx, rd, prefix, library_id, book_id, ext, mtime, copy_func
rd.outheaders['Tempfile'] = hexlify(fname.encode('utf-8'))
return rd.filesystem_file_with_custom_etag(ans, prefix, library_id, book_id, mtime, extra_etag_data)
+
+def generate_cover_worker(width, height, opf, file_name, use_roman):
+ # We have to generate the cover in a worker as it depends on Qt and needs
+ # QApplication
+ from calibre.ebooks.covers import cprefs, override_prefs, scale_cover, generate_cover, set_use_roman
+ from calibre.ebooks.metadata.opf2 import OPF
+ set_use_roman(use_roman)
+ mi = OPF(BytesIO(opf), try_to_guess_cover=False, populate_spine=False).to_book_metadata()
+ if height is None:
+ prefs = cprefs
+ else:
+ ratio = height / float(cprefs['cover_height'])
+ prefs = override_prefs(cprefs)
+ scale_cover(prefs, ratio)
+ cdata = generate_cover(mi, prefs=prefs)
+ with share_open(file_name, 'w+b') as f:
+ f.write(cdata)
+
+
+def write_generated_cover(db, book_id, width, height, destf):
+ from calibre.ebooks.metadata.opf2 import metadata_to_opf
+ mi = metadata_to_opf(db.get_metadata(book_id))
+ try:
+ fork_job('calibre.srv.content', 'generate_cover_worker', args=(width, height, mi, destf.name, get_use_roman()), no_output=True)
+ except WorkerError as err:
+ raise Exception(err.orig_tb)
+
+def generated_cover(ctx, rd, library_id, db, book_id, width=None, height=None):
+ prefix = 'generated-cover'
+ if height is not None:
+ prefix += '-%sx%s' % (width, height)
+
+ mtime = timestampfromdt(db.field_for('last_modified', book_id))
+ return create_file_copy(ctx, rd, prefix, library_id, book_id, 'jpg', mtime, partial(write_generated_cover, db, book_id, width, height))
+
def cover(ctx, rd, library_id, db, book_id, width=None, height=None):
mtime = db.cover_last_modified(book_id)
if mtime is None:
- raise HTTPNotFound('No cover for book: %r' % book_id)
+ return generated_cover(ctx, rd, library_id, db, book_id, width, height)
prefix = 'cover'
if width is None and height is None:
def copy_func(dest):
diff --git a/src/calibre/srv/utils.py b/src/calibre/srv/utils.py
index 6be716b702..15b25250df 100644
--- a/src/calibre/srv/utils.py
+++ b/src/calibre/srv/utils.py
@@ -6,7 +6,7 @@ from __future__ import (unicode_literals, division, absolute_import,
__license__ = 'GPL v3'
__copyright__ = '2015, Kovid Goyal '
-import errno, socket, select, os
+import errno, socket, select, os, re
from Cookie import SimpleCookie
from contextlib import closing
from urlparse import parse_qs
@@ -18,7 +18,7 @@ from urllib import quote as urlquote
from binascii import hexlify, unhexlify
from calibre import prints
-from calibre.constants import iswindows
+from calibre.constants import iswindows, config_dir
from calibre.srv.errors import HTTPNotFound
from calibre.utils.config_base import tweaks
from calibre.utils.localization import get_translator
@@ -505,3 +505,18 @@ class Offsets(object):
self.last_offset = last_allowed_index - delta
if self.last_offset < 0:
self.last_offset = 0
+
+_use_roman = None
+
+def get_use_roman():
+ global _use_roman
+ if _use_roman is None:
+ try:
+ with lopen(os.path.join(config_dir, 'gui.py'), 'rb') as f:
+ raw = f.read()
+ except EnvironmentError:
+ _use_roman = False
+ else:
+ m = re.search(br'use_roman_numerals_for_series_number\s*=\s*(True|False)', raw)
+ _use_roman = m is not None and m.group(1) == b'True'
+ return _use_roman