mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Allow setting the cover for a book from one of the book's formats by right clicking on the format in the Book details panel. See #1515411 (Extract cover via book details and edit metadata)
This commit is contained in:
parent
438f5a8d88
commit
692500b852
@ -7,6 +7,7 @@ __docformat__ = 'restructuredtext en'
|
|||||||
|
|
||||||
import os, shutil, copy
|
import os, shutil, copy
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
from io import BytesIO
|
||||||
|
|
||||||
from PyQt5.Qt import QMenu, QModelIndex, QTimer, QIcon, QApplication
|
from PyQt5.Qt import QMenu, QModelIndex, QTimer, QIcon, QApplication
|
||||||
|
|
||||||
@ -785,3 +786,55 @@ class EditMetadataAction(InterfaceAction):
|
|||||||
affected_books = db.set_field(field, {book_id:''})
|
affected_books = db.set_field(field, {book_id:''})
|
||||||
if affected_books:
|
if affected_books:
|
||||||
self.refresh_books_after_metadata_edit(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()
|
||||||
|
@ -130,10 +130,12 @@ def details_context_menu_event(view, ev, book_info): # {{{
|
|||||||
ofmt = fmt.upper() if fmt.startswith('ORIGINAL_') else 'ORIGINAL_' + fmt
|
ofmt = fmt.upper() if fmt.startswith('ORIGINAL_') else 'ORIGINAL_' + fmt
|
||||||
nfmt = ofmt[len('ORIGINAL_'):]
|
nfmt = ofmt[len('ORIGINAL_'):]
|
||||||
fmts = {x.upper() for x in db.formats(book_id)}
|
fmts = {x.upper() for x in db.formats(book_id)}
|
||||||
for a, t in [('remove', _('Delete the %s format')),
|
for a, t in [
|
||||||
('save', _('Save the %s format to disk')),
|
('remove', _('Delete the %s format')),
|
||||||
('restore', _('Restore the %s format')),
|
('save', _('Save the %s format to disk')),
|
||||||
('compare', ''),
|
('restore', _('Restore the %s format')),
|
||||||
|
('compare', ''),
|
||||||
|
('set_cover', _('Set the book cover from the %s file')),
|
||||||
]:
|
]:
|
||||||
if a == 'restore' and not fmt.startswith('ORIGINAL_'):
|
if a == 'restore' and not fmt.startswith('ORIGINAL_'):
|
||||||
continue
|
continue
|
||||||
@ -401,6 +403,7 @@ class BookInfo(QWebView):
|
|||||||
save_format = pyqtSignal(int, object)
|
save_format = pyqtSignal(int, object)
|
||||||
restore_format = pyqtSignal(int, object)
|
restore_format = pyqtSignal(int, object)
|
||||||
compare_format = pyqtSignal(int, object)
|
compare_format = pyqtSignal(int, object)
|
||||||
|
set_cover_format = pyqtSignal(int, object)
|
||||||
copy_link = pyqtSignal(object)
|
copy_link = pyqtSignal(object)
|
||||||
manage_author = pyqtSignal(object)
|
manage_author = pyqtSignal(object)
|
||||||
open_fmt_with = pyqtSignal(int, object, object)
|
open_fmt_with = pyqtSignal(int, object, object)
|
||||||
@ -422,7 +425,9 @@ class BookInfo(QWebView):
|
|||||||
for x, icon in [
|
for x, icon in [
|
||||||
('remove_format', 'trash.png'), ('save_format', 'save.png'),
|
('remove_format', 'trash.png'), ('save_format', 'save.png'),
|
||||||
('restore_format', 'edit-undo.png'), ('copy_link','edit-copy.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 = QAction(QIcon(I(icon)), '', self)
|
||||||
ac.current_fmt = None
|
ac.current_fmt = None
|
||||||
ac.current_url = None
|
ac.current_url = None
|
||||||
@ -459,6 +464,9 @@ class BookInfo(QWebView):
|
|||||||
def compare_format_triggerred(self):
|
def compare_format_triggerred(self):
|
||||||
self.context_action_triggered('compare_format')
|
self.context_action_triggered('compare_format')
|
||||||
|
|
||||||
|
def set_cover_format_triggerred(self):
|
||||||
|
self.context_action_triggered('set_cover_format')
|
||||||
|
|
||||||
def copy_link_triggerred(self):
|
def copy_link_triggerred(self):
|
||||||
self.context_action_triggered('copy_link')
|
self.context_action_triggered('copy_link')
|
||||||
|
|
||||||
@ -603,6 +611,7 @@ class BookDetails(QWidget): # {{{
|
|||||||
remove_metadata_item = pyqtSignal(int, object, object)
|
remove_metadata_item = pyqtSignal(int, object, object)
|
||||||
save_specific_format = pyqtSignal(int, object)
|
save_specific_format = pyqtSignal(int, object)
|
||||||
restore_specific_format = pyqtSignal(int, object)
|
restore_specific_format = pyqtSignal(int, object)
|
||||||
|
set_cover_from_format = pyqtSignal(int, object)
|
||||||
compare_specific_format = pyqtSignal(int, object)
|
compare_specific_format = pyqtSignal(int, object)
|
||||||
copy_link = pyqtSignal(object)
|
copy_link = pyqtSignal(object)
|
||||||
remote_file_dropped = pyqtSignal(object, 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.open_fmt_with.connect(self.open_fmt_with)
|
||||||
self.book_info.save_format.connect(self.save_specific_format)
|
self.book_info.save_format.connect(self.save_specific_format)
|
||||||
self.book_info.restore_format.connect(self.restore_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.compare_format.connect(self.compare_specific_format)
|
||||||
self.book_info.copy_link.connect(self.copy_link)
|
self.book_info.copy_link.connect(self.copy_link)
|
||||||
self.book_info.manage_author.connect(self.manage_author)
|
self.book_info.manage_author.connect(self.manage_author)
|
||||||
|
@ -528,6 +528,8 @@ class LayoutMixin(object): # {{{
|
|||||||
self.iactions['Save To Disk'].save_library_format_by_ids)
|
self.iactions['Save To Disk'].save_library_format_by_ids)
|
||||||
self.book_details.restore_specific_format.connect(
|
self.book_details.restore_specific_format.connect(
|
||||||
self.iactions['Remove Books'].restore_format)
|
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,
|
self.book_details.copy_link.connect(self.bd_copy_link,
|
||||||
type=Qt.QueuedConnection)
|
type=Qt.QueuedConnection)
|
||||||
self.book_details.view_device_book.connect(
|
self.book_details.view_device_book.connect(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user