diff --git a/src/calibre/db/backend.py b/src/calibre/db/backend.py index b40fcc2794..cdcb14bcf0 100644 --- a/src/calibre/db/backend.py +++ b/src/calibre/db/backend.py @@ -1214,6 +1214,13 @@ class DB(object): shutil.copyfile(candidates[0], fmt_path) return fmt_path + def apply_to_format(self, book_id, path, fname, fmt, func, missing_value=None): + path = self.format_abspath(book_id, fmt, fname, path) + if path is None: + return missing_value + with lopen(path, 'r+b') as f: + return func(f) + def format_hash(self, book_id, fmt, fname, path): path = self.format_abspath(book_id, fmt, fname, path) if path is None: diff --git a/src/calibre/db/cache.py b/src/calibre/db/cache.py index 5cb4529649..92b9a5d2eb 100644 --- a/src/calibre/db/cache.py +++ b/src/calibre/db/cache.py @@ -10,7 +10,7 @@ __docformat__ = 'restructuredtext en' import os, traceback, random, shutil, re, operator from io import BytesIO from collections import defaultdict -from functools import wraps +from functools import wraps, partial from future_builtins import zip from calibre import isbytestring @@ -1685,8 +1685,7 @@ class Cache(object): identical_book_ids = set() if mi.authors: try: - quathors = mi.authors[:20] # Too many authors causes parsing of - # the search expression to fail + quathors = mi.authors[:20] # Too many authors causes parsing of the search expression to fail query = ' and '.join('authors:"=%s"'%(a.replace('"', '')) for a in quathors) qauthors = mi.authors[20:] except ValueError: @@ -1797,5 +1796,44 @@ class Cache(object): ans[book].append(lib) return {k:tuple(sorted(v, key=sort_key)) for k, v in ans.iteritems()} + @write_api + def embed_metadata(self, book_ids, only_fmts=None): + ''' Update metadata in all formats of the specified book_ids to current metadata in the database. ''' + field = self.fields['formats'] + from calibre.ebooks.metadata.opf2 import pretty_print + from calibre.customize.ui import apply_null_metadata + from calibre.ebooks.metadata.meta import set_metadata + if only_fmts: + only_fmts = {f.lower() for f in only_fmts} + + def doit(fmt, mi, stream): + with apply_null_metadata, pretty_print: + set_metadata(stream, mi, stream_type=fmt) + stream.seek(0, os.SEEK_END) + return stream.tell() + + for book_id in book_ids: + fmts = field.table.book_col_map.get(book_id, ()) + if not fmts: + continue + mi = self.get_metadata(book_id, get_cover=True, cover_as_data=True) + try: + path = self._field_for('path', book_id).replace('/', os.sep) + except: + continue + for fmt in fmts: + if only_fmts is not None and fmt.lower() not in only_fmts: + continue + try: + name = self.fields['formats'].format_fname(book_id, fmt) + except: + continue + if name and path: + new_size = self.backend.apply_to_format(book_id, path, name, fmt, partial(doit, fmt, mi)) + if new_size is not None: + self.format_metadata_cache[book_id].get(fmt, {})['size'] = new_size + max_size = self.fields['formats'].table.update_fmt(book_id, fmt, name, new_size, self.backend) + self.fields['size'].table.update_sizes({book_id: max_size}) + # }}} diff --git a/src/calibre/gui2/actions/tweak_epub.py b/src/calibre/gui2/actions/tweak_epub.py index 2b2def20fa..5a41526ef6 100755 --- a/src/calibre/gui2/actions/tweak_epub.py +++ b/src/calibre/gui2/actions/tweak_epub.py @@ -131,16 +131,11 @@ class TweakEpubAction(InterfaceAction): 'The %s format is missing from the calibre library. You should run' ' library maintenance.') % fmt, show=True) tweak = 'ebook-edit' - self.gui.setCursor(Qt.BusyCursor) - if tprefs['update_metadata_from_calibre']: - from calibre.ebooks.metadata.opf2 import pretty_print - from calibre.ebooks.metadata.meta import set_metadata - from calibre.customize.ui import apply_null_metadata - mi = db.new_api.get_metadata(book_id, get_cover=True) - with pretty_print, apply_null_metadata, open(path, 'r+b') as f: - set_metadata(f, mi, stream_type=fmt.lower()) - notify = '%d:%s:%s:%s' % (book_id, fmt, db.library_id, db.library_path) try: + self.gui.setCursor(Qt.BusyCursor) + if tprefs['update_metadata_from_calibre']: + db.new_api.embed_metadata((book_id,), only_fmts={fmt}) + notify = '%d:%s:%s:%s' % (book_id, fmt, db.library_id, db.library_path) self.gui.job_manager.launch_gui_app(tweak, kwargs=dict(path=path, notify=notify)) time.sleep(2) finally: