From 912e8fbacd8bcd1aa2cc6993806b15a042e15c85 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 4 Jul 2012 10:07:34 +0530 Subject: [PATCH] calibredb: Add a backup_metadata command to manually run the backup to opf from the command line --- src/calibre/library/cli.py | 51 +++++++++++++++++++++++++++++++- src/calibre/library/database2.py | 18 +++++++++-- 2 files changed, 66 insertions(+), 3 deletions(-) diff --git a/src/calibre/library/cli.py b/src/calibre/library/cli.py index 6c24a1e455..d5defe96c7 100644 --- a/src/calibre/library/cli.py +++ b/src/calibre/library/cli.py @@ -999,6 +999,55 @@ def command_saved_searches(args, dbpath): return 0 +def backup_metadata_option_parser(): + parser = get_parser(_('''\ +%prog backup_metadata [options] + +Backup the metadata stored in the database into individual OPF files in each +books directory. This normally happens automatically, but you can run this +command to force re-generation of the OPF files, with the --all option. + +Note that there is normally no need to do this, as the OPF files are backed up +automatically, every time metadata is changed. +''')) + parser.add_option('--all', default=False, action='store_true', + help=_('Normally, this command only operates on books that have' + ' out of date OPF files. This option makes it operate on all' + ' books.')) + return parser + +class BackupProgress(object): + + def __init__(self): + self.total = 0 + self.count = 0 + + def __call__(self, book_id, mi, ok): + if mi is True: + self.total = book_id + else: + self.count += 1 + prints(u'%.1f%% %s - %s'%((self.count*100)/float(self.total), + book_id, mi.title)) + +def command_backup_metadata(args, dbpath): + parser = backup_metadata_option_parser() + opts, args = parser.parse_args(args) + if len(args) != 0: + parser.print_help() + return 1 + + if opts.library_path is not None: + dbpath = opts.library_path + if isbytestring(dbpath): + dbpath = dbpath.decode(preferred_encoding) + db = LibraryDatabase2(dbpath) + book_ids = None + if opts.all: + book_ids = db.all_ids() + db.dump_metadata(book_ids=book_ids, callback=BackupProgress()) + + def check_library_option_parser(): from calibre.library.check_library import CHECKS parser = get_parser(_('''\ @@ -1275,7 +1324,7 @@ COMMANDS = ('list', 'add', 'remove', 'add_format', 'remove_format', 'show_metadata', 'set_metadata', 'export', 'catalog', 'saved_searches', 'add_custom_column', 'custom_columns', 'remove_custom_column', 'set_custom', 'restore_database', - 'check_library', 'list_categories') + 'check_library', 'list_categories', 'backup_metadata') def option_parser(): diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py index 32cb6737a8..ccb9bc35b7 100644 --- a/src/calibre/library/database2.py +++ b/src/calibre/library/database2.py @@ -808,18 +808,30 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): pass def dump_metadata(self, book_ids=None, remove_from_dirtied=True, - commit=True): + commit=True, callback=None): ''' - Write metadata for each record to an individual OPF file + Write metadata for each record to an individual OPF file. If callback + is not None, it is called once at the start with the number of book_ids + being processed. And once for every book_id, with arguments (book_id, + mi, ok). ''' if book_ids is None: book_ids = [x[0] for x in self.conn.get( 'SELECT book FROM metadata_dirtied', all=True)] + + if callback is not None: + book_ids = tuple(book_ids) + callback(len(book_ids), True, False) + for book_id in book_ids: if not self.data.has_id(book_id): + if callback is not None: + callback(book_id, None, False) continue path, mi, sequence = self.get_metadata_for_dump(book_id) if path is None: + if callback is not None: + callback(book_id, mi, False) continue try: raw = metadata_to_opf(mi) @@ -829,6 +841,8 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): self.clear_dirtied(book_id, sequence) except: pass + if callback is not None: + callback(book_id, mi, True) if commit: self.conn.commit()