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