'+_(
+ 'All book formats and metadata from the selected books '
+ 'will be added to the first selected book.
'
+ 'The second and subsequently selected books will not '
+ 'be deleted or changed.
'
+ 'Please confirm you want to proceed.')
+ +'
'+_(
+ 'All book formats and metadata from the selected books will be merged '
+ 'into the first selected book.
'
+ 'After merger the second and '
+ 'subsequently selected books will be deleted.
'
+ 'All book formats of the first selected book will be kept '
+ 'and any duplicate formats in the second and subsequently selected books '
+ 'will be permanently deleted from your computer.
'
+ 'Are you sure you want to proceed?')
+ +'
'+_('You are about to merge more than 5 books. ' + 'Are you sure you want to proceed?') + +'
', 'merge_too_many_books', self): + return + self.add_formats(dest_id, src_books) + self.merge_metadata(dest_id, src_ids) + self.delete_books_after_merge(src_ids) + # leave the selection highlight on first selected book + dest_row = rows[0].row() + for row in rows: + if row.row() < rows[0].row(): + dest_row -= 1 + ci = self.library_view.model().index(dest_row, 0) + if ci.isValid(): + self.library_view.setCurrentIndex(ci) + + def add_formats(self, dest_id, src_books, replace=False): + for src_book in src_books: + if src_book: + fmt = os.path.splitext(src_book)[-1].replace('.', '').upper() + with open(src_book, 'rb') as f: + self.db.add_format(dest_id, fmt, f, index_is_id=True, + notify=False, replace=replace) + + def books_to_merge(self, rows): + src_books = [] + src_ids = [] + m = self.library_view.model() + for i, row in enumerate(rows): + id_ = m.id(row) + if i == 0: + dest_id = id_ + else: + src_ids.append(id_) + dbfmts = m.db.formats(id_, index_is_id=True) + if dbfmts: + for fmt in dbfmts: + src_books.append(m.db.format_abspath(id_, fmt, + index_is_id=True)) + return [dest_id, src_books, src_ids] + + def delete_books_after_merge(self, ids_to_delete): + self.library_view.model().delete_books_by_id(ids_to_delete) + + def merge_metadata(self, dest_id, src_ids): + db = self.library_view.model().db + dest_mi = db.get_metadata(dest_id, index_is_id=True, get_cover=True) + orig_dest_comments = dest_mi.comments + for src_id in src_ids: + src_mi = db.get_metadata(src_id, index_is_id=True, get_cover=True) + if src_mi.comments and orig_dest_comments != src_mi.comments: + if not dest_mi.comments or len(dest_mi.comments) == 0: + dest_mi.comments = src_mi.comments + else: + dest_mi.comments = unicode(dest_mi.comments) + u'\n\n' + unicode(src_mi.comments) + if src_mi.title and src_mi.title and (not dest_mi.title or + dest_mi.title == _('Unknown')): + dest_mi.title = src_mi.title + if src_mi.title and (not dest_mi.authors or dest_mi.authors[0] == + _('Unknown')): + dest_mi.authors = src_mi.authors + dest_mi.author_sort = src_mi.author_sort + if src_mi.tags: + if not dest_mi.tags: + dest_mi.tags = src_mi.tags + else: + for tag in src_mi.tags: + dest_mi.tags.append(tag) + if src_mi.cover and not dest_mi.cover: + dest_mi.cover = src_mi.cover + if not dest_mi.publisher: + dest_mi.publisher = src_mi.publisher + if not dest_mi.rating: + dest_mi.rating = src_mi.rating + if not dest_mi.series: + dest_mi.series = src_mi.series + dest_mi.series_index = src_mi.series_index + db.set_metadata(dest_id, dest_mi, ignore_errors=False) + + ############################################################################ + ############################## Save to disk ################################ def save_single_format_to_disk(self, checked): @@ -2096,6 +2238,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): self.status_bar.reset_info() if location == 'library': self.action_edit.setEnabled(True) + self.action_merge.setEnabled(True) self.action_convert.setEnabled(True) self.view_menu.actions()[1].setEnabled(True) self.action_open_containing_folder.setEnabled(True) @@ -2106,6 +2249,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): action.setEnabled(True) else: self.action_edit.setEnabled(False) + self.action_merge.setEnabled(False) self.action_convert.setEnabled(False) self.view_menu.actions()[1].setEnabled(False) self.action_open_containing_folder.setEnabled(False)