diff --git a/src/calibre/gui2/actions/edit_metadata.py b/src/calibre/gui2/actions/edit_metadata.py index 8d1562b6c5..f8b7ee8a51 100644 --- a/src/calibre/gui2/actions/edit_metadata.py +++ b/src/calibre/gui2/actions/edit_metadata.py @@ -7,6 +7,7 @@ __docformat__ = 'restructuredtext en' import os, shutil, copy from functools import partial +from io import BytesIO from PyQt5.Qt import QMenu, QModelIndex, QTimer, QIcon, QApplication @@ -785,3 +786,55 @@ class EditMetadataAction(InterfaceAction): affected_books = db.set_field(field, {book_id:''}) if affected_books: self.refresh_books_after_metadata_edit(affected_books) + + def set_cover_from_format(self, book_id, fmt): + from calibre.utils.config import prefs + from calibre.ebooks.metadata.meta import get_metadata + fmt = fmt.lower() + cdata = None + db = self.gui.current_db.new_api + if fmt == 'pdf': + pdfpath = db.format_abspath(book_id, fmt) + if pdfpath is None: + return error_dialog(self.gui, _('Format file missing'), _( + 'Cannot read cover as the %s file is missing from this book') % 'PDF', show=True) + from calibre.gui2.metadata.pdf_covers import PDFCovers + d = PDFCovers(pdfpath, parent=self.gui) + if d.exec_() == d.Accepted: + cpath = d.cover_path + if cpath: + with open(cpath, 'rb') as f: + cdata = f.read() + d.cleanup() + else: + stream = BytesIO() + try: + db.copy_format_to(book_id, fmt, stream) + except NoSuchFormat: + return error_dialog(self.gui, _('Format file missing'), _( + 'Cannot read cover as the %s file is missing from this book') % fmt.upper(), show=True) + old = prefs['read_file_metadata'] + if not old: + prefs['read_file_metadata'] = True + try: + stream.seek(0) + mi = get_metadata(stream, fmt) + except Exception: + import traceback + return error_dialog(self.gui, _('Could not read metadata'), + _('Could not read metadata from %s format')%fmt.upper(), + det_msg=traceback.format_exc(), show=True) + finally: + if old != prefs['read_file_metadata']: + prefs['read_file_metadata'] = old + if mi.cover and os.access(mi.cover, os.R_OK): + cdata = open(mi.cover).read() + elif mi.cover_data[1] is not None: + cdata = mi.cover_data[1] + if cdata is None: + return error_dialog(self.gui, _('Could not read cover'), + _('Could not read cover from %s format')%fmt.upper(), show=True) + db.set_cover({book_id:cdata}) + current_idx = self.gui.library_view.currentIndex() + self.gui.library_view.model().current_changed(current_idx, current_idx) + self.gui.refresh_cover_browser() diff --git a/src/calibre/gui2/book_details.py b/src/calibre/gui2/book_details.py index 1b53973435..eb0794e2f9 100644 --- a/src/calibre/gui2/book_details.py +++ b/src/calibre/gui2/book_details.py @@ -130,10 +130,12 @@ def details_context_menu_event(view, ev, book_info): # {{{ ofmt = fmt.upper() if fmt.startswith('ORIGINAL_') else 'ORIGINAL_' + fmt nfmt = ofmt[len('ORIGINAL_'):] fmts = {x.upper() for x in db.formats(book_id)} - for a, t in [('remove', _('Delete the %s format')), - ('save', _('Save the %s format to disk')), - ('restore', _('Restore the %s format')), - ('compare', ''), + for a, t in [ + ('remove', _('Delete the %s format')), + ('save', _('Save the %s format to disk')), + ('restore', _('Restore the %s format')), + ('compare', ''), + ('set_cover', _('Set the book cover from the %s file')), ]: if a == 'restore' and not fmt.startswith('ORIGINAL_'): continue @@ -401,6 +403,7 @@ class BookInfo(QWebView): save_format = pyqtSignal(int, object) restore_format = pyqtSignal(int, object) compare_format = pyqtSignal(int, object) + set_cover_format = pyqtSignal(int, object) copy_link = pyqtSignal(object) manage_author = pyqtSignal(object) open_fmt_with = pyqtSignal(int, object, object) @@ -422,7 +425,9 @@ class BookInfo(QWebView): for x, icon in [ ('remove_format', 'trash.png'), ('save_format', 'save.png'), ('restore_format', 'edit-undo.png'), ('copy_link','edit-copy.png'), - ('manage_author', 'user_profile.png'), ('compare_format', 'diff.png')]: + ('manage_author', 'user_profile.png'), ('compare_format', 'diff.png'), + ('set_cover_format', 'book.png'), + ]: ac = QAction(QIcon(I(icon)), '', self) ac.current_fmt = None ac.current_url = None @@ -459,6 +464,9 @@ class BookInfo(QWebView): def compare_format_triggerred(self): self.context_action_triggered('compare_format') + def set_cover_format_triggerred(self): + self.context_action_triggered('set_cover_format') + def copy_link_triggerred(self): self.context_action_triggered('copy_link') @@ -603,6 +611,7 @@ class BookDetails(QWidget): # {{{ remove_metadata_item = pyqtSignal(int, object, object) save_specific_format = pyqtSignal(int, object) restore_specific_format = pyqtSignal(int, object) + set_cover_from_format = pyqtSignal(int, object) compare_specific_format = pyqtSignal(int, object) copy_link = pyqtSignal(object) remote_file_dropped = pyqtSignal(object, object) @@ -680,6 +689,7 @@ class BookDetails(QWidget): # {{{ self.book_info.open_fmt_with.connect(self.open_fmt_with) self.book_info.save_format.connect(self.save_specific_format) self.book_info.restore_format.connect(self.restore_specific_format) + self.book_info.set_cover_format.connect(self.set_cover_from_format) self.book_info.compare_format.connect(self.compare_specific_format) self.book_info.copy_link.connect(self.copy_link) self.book_info.manage_author.connect(self.manage_author) diff --git a/src/calibre/gui2/init.py b/src/calibre/gui2/init.py index e6f1e30067..0a8a7ae110 100644 --- a/src/calibre/gui2/init.py +++ b/src/calibre/gui2/init.py @@ -528,6 +528,8 @@ class LayoutMixin(object): # {{{ self.iactions['Save To Disk'].save_library_format_by_ids) self.book_details.restore_specific_format.connect( self.iactions['Remove Books'].restore_format) + self.book_details.set_cover_from_format.connect( + self.iactions['Edit Metadata'].set_cover_from_format) self.book_details.copy_link.connect(self.bd_copy_link, type=Qt.QueuedConnection) self.book_details.view_device_book.connect(