From bd61ee0bf3ca6c26d936a62bb8e34853ccefb8d5 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 7 Feb 2011 12:16:04 -0700 Subject: [PATCH 1/5] Fix #8759 (Automerge_Option_Updates) --- src/calibre/gui2/__init__.py | 1 + src/calibre/gui2/actions/add.py | 4 +-- src/calibre/gui2/add.py | 47 +++++++++++++++++++------- src/calibre/gui2/preferences/adding.py | 8 ++++- src/calibre/gui2/preferences/adding.ui | 46 +++++++++++++++++++++---- src/calibre/library/server/content.py | 1 - 6 files changed, 85 insertions(+), 22 deletions(-) diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index 9150172fc1..92a68fa840 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -50,6 +50,7 @@ gprefs.defaults['action-layout-context-menu-device'] = ( gprefs.defaults['show_splash_screen'] = True gprefs.defaults['toolbar_icon_size'] = 'medium' +gprefs.defaults['automerge'] = 'ignore' gprefs.defaults['toolbar_text'] = 'auto' gprefs.defaults['show_child_bar'] = False gprefs.defaults['font'] = None diff --git a/src/calibre/gui2/actions/add.py b/src/calibre/gui2/actions/add.py index 4236a63340..25127d3635 100644 --- a/src/calibre/gui2/actions/add.py +++ b/src/calibre/gui2/actions/add.py @@ -244,8 +244,8 @@ class AddAction(InterfaceAction): x.decode(preferred_encoding, 'replace') for x in self._adder.merged_books]) info_dialog(self.gui, _('Merged some books'), - _('Some duplicates were found and merged into the ' - 'following existing books:'), det_msg=books, show=True) + _('The following duplicate books were found and incoming book formats were ' + 'processed and merged into your Calibre database according to your automerge settings:'), det_msg=books, show=True) if getattr(self._adder, 'critical', None): det_msg = [] for name, log in self._adder.critical.items(): diff --git a/src/calibre/gui2/add.py b/src/calibre/gui2/add.py index 026fabea07..086f40feee 100644 --- a/src/calibre/gui2/add.py +++ b/src/calibre/gui2/add.py @@ -8,7 +8,7 @@ from functools import partial from PyQt4.Qt import QThread, QObject, Qt, QProgressDialog, pyqtSignal, QTimer from calibre.gui2.dialogs.progress import ProgressDialog -from calibre.gui2 import question_dialog, error_dialog, info_dialog +from calibre.gui2 import question_dialog, error_dialog, info_dialog, gprefs from calibre.ebooks.metadata.opf2 import OPF from calibre.ebooks.metadata import MetaInformation from calibre.constants import preferred_encoding, filesystem_encoding, DEBUG @@ -179,23 +179,46 @@ class DBAdder(QObject): # {{{ cover = f.read() orig_formats = formats formats = [f for f in formats if not f.lower().endswith('.opf')] - if prefs['add_formats_to_existing']: + if prefs['add_formats_to_existing']: #automerge is on identical_book_list = self.db.find_identical_books(mi) - - if identical_book_list: # books with same author and nearly same title exist in db + if identical_book_list: # books with same author and nearly same title exist in db self.merged_books.add(mi.title) + a_new_record_has_been_created = False for identical_book in identical_book_list: - self.add_formats(identical_book, formats, replace=False) - else: - id = self.db.create_book_entry(mi, cover=cover, add_duplicates=True) + if gprefs['automerge'] == 'ignore': + self.add_formats(identical_book, formats, replace=False) + if gprefs['automerge'] == 'overwrite': + self.add_formats(identical_book, formats, replace=True) + if gprefs['automerge'] == 'new record' and not a_new_record_has_been_created: + ''' + We are here because we have at least one book record in the db that matches the one file/format being processed + We need to check if the file/format being processed matches a format in the matching book record. + If so, create new record (as below), else, add to existing record, as above. + Test if format exists in matching record. identical_book is an id, formats is a FQPN path in a list + ''' + for path in formats: + fmt = os.path.splitext(path)[-1].replace('.', '').upper() + ib_fmts = self.db.formats(identical_book, index_is_id=True) + if ib_fmts and fmt in ib_fmts: # Create a new record + if not a_new_record_has_been_created: + id_ = self.db.create_book_entry(mi, cover=cover, add_duplicates=True) + self.number_of_books_added += 1 + self.add_formats(id_, formats) + a_new_record_has_been_created = True + else: #new record not required + self.add_formats(identical_book, formats, replace=False) + + else: # books with same author and nearly same title do not exist in db + id_ = self.db.create_book_entry(mi, cover=cover, add_duplicates=True) self.number_of_books_added += 1 - self.add_formats(id, formats) - else: - id = self.db.create_book_entry(mi, cover=cover, add_duplicates=False) - if id is None: + self.add_formats(id_, formats) + + else: #automerge is off + id_ = self.db.create_book_entry(mi, cover=cover, add_duplicates=False) + if id_ is None: self.duplicates.append((mi, cover, orig_formats)) else: - self.add_formats(id, formats) + self.add_formats(id_, formats) self.number_of_books_added += 1 else: self.names.append(name) diff --git a/src/calibre/gui2/preferences/adding.py b/src/calibre/gui2/preferences/adding.py index e919d53b64..b4c4ce846a 100644 --- a/src/calibre/gui2/preferences/adding.py +++ b/src/calibre/gui2/preferences/adding.py @@ -12,6 +12,7 @@ from calibre.gui2.preferences import ConfigWidgetBase, test_widget, \ from calibre.gui2.preferences.adding_ui import Ui_Form from calibre.utils.config import prefs from calibre.gui2.widgets import FilenamePattern +from calibre.gui2 import gprefs class ConfigWidget(ConfigWidgetBase, Ui_Form): @@ -23,18 +24,23 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): r('read_file_metadata', prefs) r('swap_author_names', prefs) r('add_formats_to_existing', prefs) + choices = [ + (_('Ignore duplicate incoming formats'), 'ignore'), + (_('Overwrite existing duplicate formats'), 'overwrite'), + (_('Create new record for each duplicate format'), 'new record')] + r('automerge', gprefs, choices=choices) r('new_book_tags', prefs, setting=CommaSeparatedList) self.filename_pattern = FilenamePattern(self) self.metadata_box.layout().insertWidget(0, self.filename_pattern) self.filename_pattern.changed_signal.connect(self.changed_signal.emit) - def initialize(self): ConfigWidgetBase.initialize(self) self.filename_pattern.blockSignals(True) self.filename_pattern.initialize() self.filename_pattern.blockSignals(False) + self.opt_automerge.setEnabled(self.opt_add_formats_to_existing.isChecked()) def restore_defaults(self): ConfigWidgetBase.restore_defaults(self) diff --git a/src/calibre/gui2/preferences/adding.ui b/src/calibre/gui2/preferences/adding.ui index 75e6c466f0..f9a2c74444 100644 --- a/src/calibre/gui2/preferences/adding.ui +++ b/src/calibre/gui2/preferences/adding.ui @@ -6,7 +6,7 @@ 0 0 - 750 + 753 339 @@ -58,16 +58,33 @@ - + - If an existing book with a similar title and author is found that does not have the format being added, the format is added -to the existing book, instead of creating a new entry. If the existing book already has the format, then it is silently ignored. + Automerge: If books with similar titles and authors found, merge the incoming formats automatically into +existing book records. The box to the right controls what happens when an existing record already has +the incoming format. Note that this option also affects the Copy to library action. Title match ignores leading indefinite articles ("the", "a", "an"), punctuation, case, etc. Author match is exact. - If books with similar titles and authors found, &merge the new files automatically + &Automerge added books if they already exist in the calibre library: + + + + + + + Automerge: If books with similar titles and authors found, merge the incoming formats automatically into +existing book records. This box controls what happens when an existing record already has +the incoming format: + +Ignore duplicate incoming files - means that existing files in your calibre library will not be replaced +Overwrite existing duplicate files - means that existing files in your calibre library will be replaced +Create new record for each duplicate file - means that a new book entry will be created for each duplicate file + +Title matching ignores leading indefinite articles ("the", "a", "an"), punctuation, case, etc. +Author matching is exact. @@ -113,5 +130,22 @@ Title match ignores leading indefinite articles ("the", "a", - + + + opt_add_formats_to_existing + toggled(bool) + opt_automerge + setEnabled(bool) + + + 406 + 83 + + + 457 + 83 + + + + diff --git a/src/calibre/library/server/content.py b/src/calibre/library/server/content.py index 62d08aa2c3..11ea2b951e 100644 --- a/src/calibre/library/server/content.py +++ b/src/calibre/library/server/content.py @@ -124,7 +124,6 @@ class ContentServer(object): cherrypy.request.headers.get('Want-OPDS-Catalog', 919) != 919 or \ ua.startswith('Stanza') - # A better search would be great want_mobile = self.is_mobile_browser(ua) if self.opts.develop and not want_mobile: cherrypy.log('User agent: '+ua) From 0cf432315be56ff8b75e98a167411fc3308c4b2b Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 7 Feb 2011 12:31:04 -0700 Subject: [PATCH 2/5] ... --- src/calibre/manual/faq.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/calibre/manual/faq.rst b/src/calibre/manual/faq.rst index 9c02ace0e8..cdae20ea3b 100644 --- a/src/calibre/manual/faq.rst +++ b/src/calibre/manual/faq.rst @@ -327,12 +327,14 @@ Now coming to author name sorting: * Authors in the Tag Browser are sorted by the sort value for the **authors**. Remember that this is different from the Author sort field for a book. * By default, this sort algorithm assumes that the author name is in ``First name Last name`` format and generates a ``Last name, First name`` sort value. * You can change this algorithm by going to Preferences->Tweaks and setting the :guilabel:`author_sort_copy_method` tweak. - * You can force |app| to recalculate the author sort values for every author by right clicking on any author and selecting :guilabel:`Manage authors` - * You can force |app| to recalculate the author sort values for all books by using the bulk metadata edit dialog (select all books and click edit metadata) - * When recalculating the author sort values for books, |app| uses the author sort values for each individual author. + * You can force |app| to recalculate the author sort values for every author by right clicking on any author and selecting :guilabel:`Manage authors`, then pushing the `Recalculate all author sort values` button. Do this after you have set the author_sort_copy_method tweak to what you want. + * You can force |app| to recalculate the author sort values for all books by using the bulk metadata edit dialog (select all books and click edit metadata, check the `Automatically set author sort` checkbox, then press OK.) + * When recalculating the author sort values for books, |app| uses the author sort values for each individual author. Therefore, ensure that the individual author sort values are correct before recalculating the books' author sort values. * You can control whether the Tag Browser display authors using their names or their sort values by setting the :guilabel:`categories_use_field_for_author_name` tweak in Preferences->Tweaks -With all this flexibility, it is possible to have |app| manage your author names however you like. For example, one common request is to have |app| display author names LN, FN. To do this first set the ``author_sort_copy_method`` to ``copy``. Then change all author names to LN, FN via the Manage authors dialog. Then have |app| recalculate author sort values as described above. +With all this flexibility, it is possible to have |app| manage your author names however you like. For example, one common request is to have |app| display author names LN, FN. To do this first set the ``author_sort_copy_method`` to ``copy``. Then change all author names to LN, FN via the Manage authors dialog. Then have |app| recalculate author sort values for both authors and books as described above. + +Note that you can set an individual author's sort value to whatever you want using :guilabel:`Manage authors`. This is useful when dealing with names that |app| will not get right, such as complex multi-part names like Miguel de Cervantes Saavedra or when dealing with Asian names like Sun Tzu. Why doesn't |app| let me store books in my own directory structure? From ae93283d778057a8e54597867d97a50e82d35bcf Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 7 Feb 2011 13:21:04 -0700 Subject: [PATCH 3/5] Fix #8854 (updated recipe for Newyorker) --- resources/recipes/new_yorker.recipe | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/recipes/new_yorker.recipe b/resources/recipes/new_yorker.recipe index d69a4df24f..9eeb8b31ee 100644 --- a/resources/recipes/new_yorker.recipe +++ b/resources/recipes/new_yorker.recipe @@ -54,10 +54,10 @@ class NewYorker(BasicNewsRecipe): ,dict(attrs={'id':['show-header','show-footer'] }) ] remove_attributes = ['lang'] - feeds = [(u'The New Yorker', u'http://www.newyorker.com/services/rss/feeds/everything.xml')] + feeds = [(u'The New Yorker', u'http://www.newyorker.com/services/mrss/feeds/everything.xml')] def print_version(self, url): - return 'http://www.newyorker.com' + url + '?printable=true' + return url + '?printable=true' def image_url_processor(self, baseurl, url): return url.strip() From 01dc213d7030cad9d014bfb037601421c3289ac1 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 7 Feb 2011 13:32:12 -0700 Subject: [PATCH 4/5] Fix #8857 (Using calibre with HTC Desire (android)) --- src/calibre/devices/android/driver.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/calibre/devices/android/driver.py b/src/calibre/devices/android/driver.py index 5912e40a69..11d636791b 100644 --- a/src/calibre/devices/android/driver.py +++ b/src/calibre/devices/android/driver.py @@ -19,10 +19,15 @@ class ANDROID(USBMS): VENDOR_ID = { # HTC - 0x0bb4 : { 0x0c02 : [0x100, 0x0227, 0x0226], 0x0c01 : [0x100, - 0x0227, 0x0226], 0x0ff9 - : [0x0100, 0x0227, 0x0226], 0x0c87: [0x0100, 0x0227, 0x0226], - 0xc92 : [0x100], 0xc97: [0x226], 0xc99 : [0x0100]}, + 0x0bb4 : { 0x0c02 : [0x100, 0x0227, 0x0226], + 0x0c01 : [0x100, 0x0227, 0x0226], + 0x0ff9 : [0x0100, 0x0227, 0x0226], + 0x0c87 : [0x0100, 0x0227, 0x0226], + 0xc92 : [0x100], + 0xc97 : [0x226], + 0xc99 : [0x0100], + 0xca3 : [0x100], + }, # Eken 0x040d : { 0x8510 : [0x0001], 0x0851 : [0x1] }, From 8a93808ccc246be23706c8a0ccc291ad2f32d8be Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 7 Feb 2011 13:43:36 -0700 Subject: [PATCH 5/5] Fix #8856 (add new device - inves wibook 600) --- src/calibre/devices/eb600/driver.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/calibre/devices/eb600/driver.py b/src/calibre/devices/eb600/driver.py index e38f72aea5..5374c6c4e2 100644 --- a/src/calibre/devices/eb600/driver.py +++ b/src/calibre/devices/eb600/driver.py @@ -172,10 +172,10 @@ class INVESBOOK(EB600): gui_name = 'Inves Book 600' FORMATS = ['epub', 'mobi', 'prc', 'fb2', 'html', 'pdf', 'rtf', 'txt'] + BCD = [0x110, 0x323] - VENDOR_NAME = 'INVES_E6' - WINDOWS_MAIN_MEM = '00INVES_E600' - WINDOWS_CARD_A_MEM = '00INVES_E600' + VENDOR_NAME = ['INVES_E6', 'INVES-WI'] + WINDOWS_MAIN_MEM = WINDOWS_CARD_A_MEM = ['00INVES_E600', 'INVES-WIBOOK'] class BOOQ(EB600): name = 'Booq Device Interface'