diff --git a/src/calibre/customize/ui.py b/src/calibre/customize/ui.py index 4d97e972f1..61a57f3222 100644 --- a/src/calibre/customize/ui.py +++ b/src/calibre/customize/ui.py @@ -364,7 +364,8 @@ def set_file_type_metadata(stream, mi, ftype, report_error=None): break except: if report_error is None: - print 'Failed to set metadata for', repr(getattr(mi, 'title', '')) + from calibre import prints + prints('Failed to set metadata for the', ftype.upper(), 'format of:', getattr(mi, 'title', ''), file=sys.stderr) traceback.print_exc() else: report_error(mi, ftype, traceback.format_exc()) diff --git a/src/calibre/db/cache.py b/src/calibre/db/cache.py index 41ba5adc41..01beef2482 100644 --- a/src/calibre/db/cache.py +++ b/src/calibre/db/cache.py @@ -1797,7 +1797,7 @@ class Cache(object): 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, report_error=None): + def embed_metadata(self, book_ids, only_fmts=None, report_error=None, report_progress=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 @@ -1812,7 +1812,7 @@ class Cache(object): stream.seek(0, os.SEEK_END) return stream.tell() - for book_id in book_ids: + for i, book_id in enumerate(book_ids): fmts = field.table.book_col_map.get(book_id, ()) if not fmts: continue @@ -1834,6 +1834,8 @@ class Cache(object): 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}) + if report_progress is not None: + report_progress(i+1, len(book_ids), mi) # }}} diff --git a/src/calibre/library/cli.py b/src/calibre/library/cli.py index f484c379d1..f93639121a 100644 --- a/src/calibre/library/cli.py +++ b/src/calibre/library/cli.py @@ -583,6 +583,43 @@ an OPF file. ' with the --field option')) return parser +def embed_metadata_option_parser(): + parser = get_parser(_( +''' +%prog embed_metadata [options] book_id + +Update the metadata in the actual book files stored in the calibre library from +the metadata in the calibre database. Normally, metadata is updated only when +exporting files from calibre, this command is useful if you want the files to +be updated in place. Note that different file formats support different amounts +of metadata. You can use the special value 'all' for book_id to update metadata +in all books. You can also specify many book ids separated by spaces and id ranges +separated by hyphens. For example: %prog embed_metadata 1 2 10-15 23''')) + parser.add_option('-f', '--only-formats', action='append', default=[], help=_( + 'Only update metadata in files of the specified format. Specify it multiple' + ' times for multiple formats. Be default, all formats are updated.')) + return parser + +def command_embed_metadata(args, dbpath): + parser = embed_metadata_option_parser() + opts, args = parser.parse_args(sys.argv[0:1]+args) + db = get_db(dbpath, opts) + ids = set() + for x in args[1:]: + if x == 'all': + ids = db.new_api.all_book_ids() + break + parts = x.split('-') + if len(parts) == 1: + ids.add(int(parts[0])) + else: + ids |= {x for x in xrange(int(parts[0], int(parts[1])))} + only_fmts = opts.only_formats or None + def progress(i, total, mi): + prints(_('Processed {0} ({1} of {2})').format(mi.title, i, total)) + db.new_api.embed_metadata(ids, only_fmts=only_fmts, report_progress=progress) + send_message() + def command_set_metadata(args, dbpath): parser = set_metadata_option_parser() opts, args = parser.parse_args(sys.argv[0:1]+args) @@ -1463,7 +1500,7 @@ COMMANDS = ('list', 'add', 'remove', 'add_format', 'remove_format', 'saved_searches', 'add_custom_column', 'custom_columns', 'remove_custom_column', 'set_custom', 'restore_database', 'check_library', 'list_categories', 'backup_metadata', - 'clone') + 'clone', 'embed_metadata') def option_parser():