This commit is contained in:
Kovid Goyal 2020-11-23 09:33:03 +05:30
commit fd97af9b1d
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C

View File

@ -9,6 +9,8 @@ from contextlib import contextmanager
from optparse import OptionGroup, OptionValueError from optparse import OptionGroup, OptionValueError
from calibre import prints from calibre import prints
from calibre.db.utils import find_identical_books
from calibre.db.copy_to_library import automerge_book
from calibre.db.adding import ( from calibre.db.adding import (
cdb_find_in_dir, cdb_recursive_find, compile_rule, create_format_map, cdb_find_in_dir, cdb_recursive_find, compile_rule, create_format_map,
run_import_plugins, run_import_plugins_before_metadata run_import_plugins, run_import_plugins_before_metadata
@ -19,6 +21,7 @@ from calibre.ebooks.metadata.meta import get_metadata, metadata_from_formats
from calibre.ptempfile import TemporaryDirectory from calibre.ptempfile import TemporaryDirectory
from calibre.srv.changes import books_added from calibre.srv.changes import books_added
from calibre.utils.localization import canonicalize_lang from calibre.utils.localization import canonicalize_lang
from calibre.utils.config import tweaks
from polyglot.builtins import unicode_type from polyglot.builtins import unicode_type
readonly = False readonly = False
@ -35,7 +38,7 @@ def empty(db, notify_changes, is_remote, args):
def book(db, notify_changes, is_remote, args): def book(db, notify_changes, is_remote, args):
data, fname, fmt, add_duplicates, otitle, oauthors, oisbn, otags, oseries, oseries_index, ocover, oidentifiers, olanguages = args data, fname, fmt, add_duplicates, otitle, oauthors, oisbn, otags, oseries, oseries_index, ocover, oidentifiers, olanguages, oautomerge = args
with add_ctx(), TemporaryDirectory('add-single') as tdir, run_import_plugins_before_metadata(tdir): with add_ctx(), TemporaryDirectory('add-single') as tdir, run_import_plugins_before_metadata(tdir):
if is_remote: if is_remote:
with lopen(os.path.join(tdir, fname), 'wb') as f: with lopen(os.path.join(tdir, fname), 'wb') as f:
@ -65,14 +68,26 @@ def book(db, notify_changes, is_remote, args):
if ocover: if ocover:
mi.cover = None mi.cover = None
mi.cover_data = ocover mi.cover_data = ocover
ids, duplicates = db.add_books( identical_book_list,added_ids,updated_ids=set(),set(),set()
[(mi, {fmt: path})], add_duplicates=add_duplicates, run_hooks=False) if oautomerge:
identical_books_data = identical_books_data = db.data_for_find_identical_books()
identical_book_list = find_identical_books(mi, identical_books_data)
add_duplicates=True
if len(identical_book_list) > 0:
for book_id in identical_book_list:
db.add_format(book_id, fmt, path, replace='overwrite', run_hooks=False)
updated_ids=identical_book_list
duplicates=False
else:
added_ids, duplicates = db.add_books(
[(mi, {fmt: path})], add_duplicates=add_duplicates, run_hooks=False)
if is_remote: if is_remote:
notify_changes(books_added(ids)) notify_changes(books_added(added_ids))
notify_changes(books_added(updated_ids))
db.dump_metadata() db.dump_metadata()
return ids, bool(duplicates), mi.title return added_ids,updated_ids, bool(duplicates), mi.title
def format_group(db, notify_changes, is_remote, args): def format_group(db, notify_changes, is_remote, args):
@ -140,7 +155,7 @@ def add_ctx():
def do_add( def do_add(
dbctx, paths, one_book_per_directory, recurse, add_duplicates, otitle, oauthors, dbctx, paths, one_book_per_directory, recurse, add_duplicates, otitle, oauthors,
oisbn, otags, oseries, oseries_index, ocover, oidentifiers, olanguages, oisbn, otags, oseries, oseries_index, ocover, oidentifiers, olanguages,
compiled_rules compiled_rules, oautomerge
): ):
with add_ctx(): with add_ctx():
files, dirs = [], [] files, dirs = [], []
@ -154,18 +169,20 @@ def do_add(
else: else:
prints(path, 'not found') prints(path, 'not found')
file_duplicates, added_ids = [], set() file_duplicates, added_ids, merged_ids = [], set(), set()
for book in files: for book in files:
fmt = os.path.splitext(book)[1] fmt = os.path.splitext(book)[1]
fmt = fmt[1:] if fmt else None fmt = fmt[1:] if fmt else None
if not fmt: if not fmt:
continue continue
ids, dups, book_title = dbctx.run( aids, mids, dups, book_title = dbctx.run(
'add', 'book', dbctx.path(book), os.path.basename(book), fmt, add_duplicates, 'add', 'book', dbctx.path(book), os.path.basename(book), fmt, add_duplicates,
otitle, oauthors, oisbn, otags, oseries, oseries_index, serialize_cover(ocover) if ocover else None, otitle, oauthors, oisbn, otags, oseries, oseries_index, serialize_cover(ocover) if ocover else None,
oidentifiers, olanguages oidentifiers, olanguages, oautomerge
) )
added_ids |= set(ids) added_ids |= set(aids)
merged_ids |= set(mids)
if dups: if dups:
file_duplicates.append((book_title, book)) file_duplicates.append((book_title, book))
@ -201,7 +218,7 @@ def do_add(
_( _(
'The following books were not added as ' 'The following books were not added as '
'they already exist in the database ' 'they already exist in the database '
'(see --duplicates option):' '(see --duplicates option or --automerge option):'
), ),
file=sys.stderr file=sys.stderr
) )
@ -216,6 +233,8 @@ def do_add(
if added_ids: if added_ids:
prints(_('Added book ids: %s') % (', '.join(map(unicode_type, added_ids)))) prints(_('Added book ids: %s') % (', '.join(map(unicode_type, added_ids))))
if merged_ids:
prints(_('Updated book ids: %s') % (', '.join(map(unicode_type, merged_ids))))
def option_parser(get_parser, args): def option_parser(get_parser, args):
@ -238,6 +257,15 @@ the directory related options below.
'Add books to database even if they already exist. Comparison is done based on book titles.' 'Add books to database even if they already exist. Comparison is done based on book titles.'
) )
) )
parser.add_option(
'-m',
'--automerge',
action='store_true',
default=False,
help=_(
'Add or upgrade existing book(s) to database. Comparison is done based on book titles, autor and language.\nSearch the library for the specified book and decide: \n * To update its format and language on the library if the book is newer than the existing one in the library.\n * To add to the library if the format and language does not exist.\n * To discard action if none of the above.'
)
)
parser.add_option( parser.add_option(
'-e', '-e',
'--empty', '--empty',
@ -379,6 +407,6 @@ def main(opts, args, dbctx):
do_add( do_add(
dbctx, args, opts.one_book_per_directory, opts.recurse, opts.duplicates, dbctx, args, opts.one_book_per_directory, opts.recurse, opts.duplicates,
opts.title, aut, opts.isbn, tags, opts.series, opts.series_index, opts.cover, opts.title, aut, opts.isbn, tags, opts.series, opts.series_index, opts.cover,
identifiers, lcodes, opts.filters identifiers, lcodes, opts.filters, opts.automerge
) )
return 0 return 0