mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Add formats to existing records
This commit is contained in:
parent
f6c8da4ada
commit
8ee99309e1
@ -13,9 +13,11 @@ from calibre.gui2 import question_dialog, error_dialog, info_dialog
|
|||||||
from calibre.ebooks.metadata.opf2 import OPF
|
from calibre.ebooks.metadata.opf2 import OPF
|
||||||
from calibre.ebooks.metadata import MetaInformation
|
from calibre.ebooks.metadata import MetaInformation
|
||||||
from calibre.constants import preferred_encoding, filesystem_encoding
|
from calibre.constants import preferred_encoding, filesystem_encoding
|
||||||
|
from calibre.library.database2 import LibraryDatabase2
|
||||||
|
from calibre.utils.config import prefs
|
||||||
|
|
||||||
class DuplicatesAdder(QThread):
|
class DuplicatesAdder(QThread):
|
||||||
|
# Add duplicate books
|
||||||
def __init__(self, parent, db, duplicates, db_adder):
|
def __init__(self, parent, db, duplicates, db_adder):
|
||||||
QThread.__init__(self, parent)
|
QThread.__init__(self, parent)
|
||||||
self.db, self.db_adder = db, db_adder
|
self.db, self.db_adder = db, db_adder
|
||||||
@ -27,6 +29,7 @@ class DuplicatesAdder(QThread):
|
|||||||
formats = [f for f in formats if not f.lower().endswith('.opf')]
|
formats = [f for f in formats if not f.lower().endswith('.opf')]
|
||||||
id = self.db.create_book_entry(mi, cover=cover,
|
id = self.db.create_book_entry(mi, cover=cover,
|
||||||
add_duplicates=True)
|
add_duplicates=True)
|
||||||
|
# here we add all the formats for dupe book record created above
|
||||||
self.db_adder.add_formats(id, formats)
|
self.db_adder.add_formats(id, formats)
|
||||||
self.db_adder.number_of_books_added += 1
|
self.db_adder.number_of_books_added += 1
|
||||||
self.emit(SIGNAL('added(PyQt_PyObject)'), count)
|
self.emit(SIGNAL('added(PyQt_PyObject)'), count)
|
||||||
@ -125,6 +128,33 @@ class DBAdder(Thread):
|
|||||||
fmts[-1] = fmt
|
fmts[-1] = fmt
|
||||||
return fmts
|
return fmts
|
||||||
|
|
||||||
|
def fuzzy_title(self, title):
|
||||||
|
indefinites = ['the', 'a', 'an']
|
||||||
|
removals = [';', ':', ',', '\'', '[', ']', '(', ')', '{', '}', '<', '>']
|
||||||
|
replacements = ['.', '_', '-']
|
||||||
|
title = title.strip().lower()
|
||||||
|
for removal in removals:
|
||||||
|
title = title.replace(removal, '')
|
||||||
|
for replacement in replacements:
|
||||||
|
title = title.replace(replacement, ' ')
|
||||||
|
title_split = title.split()
|
||||||
|
for indefinite in indefinites:
|
||||||
|
if title_split[0] == indefinite:
|
||||||
|
title = ' '.join(title_split[1:])
|
||||||
|
return title
|
||||||
|
|
||||||
|
def find_identical_books(self, mi):
|
||||||
|
author_id = [unicode(self.db.conn.get('SELECT id FROM authors WHERE name = ?;', ([mi.author[0]]), all=False))]
|
||||||
|
identical_book_ids = []
|
||||||
|
book_ids = self.db.conn.get('SELECT book FROM books_authors_link WHERE author = ?;', (author_id), all=True)
|
||||||
|
for book_id in book_ids:
|
||||||
|
fbook_title = self.db.conn.get('SELECT title FROM books WHERE id = ?;', (book_id), all=False)
|
||||||
|
fbook_title = self.fuzzy_title(fbook_title)
|
||||||
|
mbook_title = self.fuzzy_title(mi.title)
|
||||||
|
if fbook_title == mbook_title:
|
||||||
|
identical_book_ids.append(book_id)
|
||||||
|
return identical_book_ids
|
||||||
|
|
||||||
def add(self, id, opf, cover, name):
|
def add(self, id, opf, cover, name):
|
||||||
formats = self.ids.pop(id)
|
formats = self.ids.pop(id)
|
||||||
if opf.endswith('.error'):
|
if opf.endswith('.error'):
|
||||||
@ -145,16 +175,30 @@ class DBAdder(Thread):
|
|||||||
if self.db is not None:
|
if self.db is not None:
|
||||||
if cover:
|
if cover:
|
||||||
cover = open(cover, 'rb').read()
|
cover = open(cover, 'rb').read()
|
||||||
id = self.db.create_book_entry(mi, cover=cover, add_duplicates=False)
|
if prefs['add_formats_to_existing']:
|
||||||
self.number_of_books_added += 1
|
identical_book_list = self.find_identical_books(mi)
|
||||||
if id is None:
|
if (identical_book_list): # books with same author and nearly same title exist in db
|
||||||
self.duplicates.append((mi, cover, formats))
|
for identical_book in identical_book_list:
|
||||||
|
formats = [f for f in formats if not f.lower().endswith('.opf')]
|
||||||
|
self.add_formats(identical_book[0], formats)
|
||||||
|
else:
|
||||||
|
id = self.db.create_book_entry(mi, cover=cover, add_duplicates=True)
|
||||||
|
self.number_of_books_added += 1 # what does this do?
|
||||||
|
formats = [f for f in formats if not f.lower().endswith('.opf')]
|
||||||
|
self.add_formats(id, formats)
|
||||||
else:
|
else:
|
||||||
formats = [f for f in formats if not f.lower().endswith('.opf')]
|
if cover:
|
||||||
self.add_formats(id, formats)
|
cover = open(cover, 'rb').read()
|
||||||
|
id = self.db.create_book_entry(mi, cover=cover, add_duplicates=False)
|
||||||
|
self.number_of_books_added += 1
|
||||||
|
if id is None:
|
||||||
|
self.duplicates.append((mi, cover, formats))
|
||||||
|
else:
|
||||||
|
formats = [f for f in formats if not f.lower().endswith('.opf')]
|
||||||
|
self.add_formats(id, formats)
|
||||||
else:
|
else:
|
||||||
self.names.append(name)
|
self.names.append(name)
|
||||||
self.paths.append(formats[0])
|
self.path.append(formats[0])
|
||||||
self.infos.append(mi)
|
self.infos.append(mi)
|
||||||
return mi.title
|
return mi.title
|
||||||
|
|
||||||
|
@ -44,6 +44,7 @@ class AddSave(QTabWidget, Ui_TabWidget):
|
|||||||
self.filename_pattern = FilenamePattern(self)
|
self.filename_pattern = FilenamePattern(self)
|
||||||
self.metadata_box.layout().insertWidget(0, self.filename_pattern)
|
self.metadata_box.layout().insertWidget(0, self.filename_pattern)
|
||||||
self.opt_swap_author_names.setChecked(prefs['swap_author_names'])
|
self.opt_swap_author_names.setChecked(prefs['swap_author_names'])
|
||||||
|
self.opt_add_formats_to_existing.setChecked(prefs['add_formats_to_existing'])
|
||||||
help = '\n'.join(textwrap.wrap(c.get_option('template').help, 75))
|
help = '\n'.join(textwrap.wrap(c.get_option('template').help, 75))
|
||||||
self.save_template.initialize('save_to_disk', opts.template, help)
|
self.save_template.initialize('save_to_disk', opts.template, help)
|
||||||
self.send_template.initialize('send_to_device', opts.send_template, help)
|
self.send_template.initialize('send_to_device', opts.send_template, help)
|
||||||
@ -69,6 +70,7 @@ class AddSave(QTabWidget, Ui_TabWidget):
|
|||||||
pattern = self.filename_pattern.commit()
|
pattern = self.filename_pattern.commit()
|
||||||
prefs['filename_pattern'] = pattern
|
prefs['filename_pattern'] = pattern
|
||||||
prefs['swap_author_names'] = bool(self.opt_swap_author_names.isChecked())
|
prefs['swap_author_names'] = bool(self.opt_swap_author_names.isChecked())
|
||||||
|
prefs['add_formats_to_existing'] = bool(self.opt_add_formats_to_existing.isChecked())
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -49,6 +49,16 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0" colspan="2">
|
<item row="2" column="0" colspan="2">
|
||||||
|
<widget class="QCheckBox" name="opt_add_formats_to_existing">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Use with caution, this option will overwrite old copies of book with new copies in same format. Title match ignores leading indefinite articles ("the", "a", "an"), punctuation, case, etc.</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Add new formats to existing record of same book. (Caution: overwrites previous same format with new - matches author exactly, fuzzy matches title.)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0" colspan="2">
|
||||||
<widget class="QGroupBox" name="metadata_box">
|
<widget class="QGroupBox" name="metadata_box">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>&Configure metadata from file name</string>
|
<string>&Configure metadata from file name</string>
|
||||||
|
@ -670,6 +670,8 @@ def _prefs():
|
|||||||
help=_('The priority of worker processes'))
|
help=_('The priority of worker processes'))
|
||||||
c.add_opt('swap_author_names', default=False,
|
c.add_opt('swap_author_names', default=False,
|
||||||
help=_('Swap author first and last names when reading metadata'))
|
help=_('Swap author first and last names when reading metadata'))
|
||||||
|
c.add_opt('add_formats_to_existing', default=False,
|
||||||
|
help=_('Add new formats to existing book records'))
|
||||||
|
|
||||||
c.add_opt('migrated', default=False, help='For Internal use. Don\'t modify.')
|
c.add_opt('migrated', default=False, help='For Internal use. Don\'t modify.')
|
||||||
return c
|
return c
|
||||||
|
Loading…
x
Reference in New Issue
Block a user