mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Fix memory leak when queueing books for bulk convert
This commit is contained in:
parent
a4dd30cea5
commit
a1b42542e1
@ -18,6 +18,24 @@ from calibre.ebooks.metadata.opf2 import OPFCreator
|
|||||||
from calibre.ptempfile import PersistentTemporaryFile
|
from calibre.ptempfile import PersistentTemporaryFile
|
||||||
from calibre.gui2.convert import Widget
|
from calibre.gui2.convert import Widget
|
||||||
|
|
||||||
|
def create_opf_file(db, book_id):
|
||||||
|
mi = db.get_metadata(book_id, index_is_id=True)
|
||||||
|
mi.application_id = uuid.uuid4()
|
||||||
|
opf = OPFCreator(os.getcwdu(), mi)
|
||||||
|
opf_file = PersistentTemporaryFile('.opf')
|
||||||
|
opf.render(opf_file)
|
||||||
|
opf_file.close()
|
||||||
|
return mi, opf_file
|
||||||
|
|
||||||
|
def create_cover_file(db, book_id):
|
||||||
|
cover = db.cover(book_id, index_is_id=True)
|
||||||
|
cf = None
|
||||||
|
if cover:
|
||||||
|
cf = PersistentTemporaryFile('.jpeg')
|
||||||
|
cf.write(cover)
|
||||||
|
cf.close()
|
||||||
|
return cf
|
||||||
|
|
||||||
class MetadataWidget(Widget, Ui_Form):
|
class MetadataWidget(Widget, Ui_Form):
|
||||||
|
|
||||||
TITLE = _('Metadata')
|
TITLE = _('Metadata')
|
||||||
@ -181,12 +199,7 @@ class MetadataWidget(Widget, Ui_Form):
|
|||||||
self.cover_file = self.opf_file = None
|
self.cover_file = self.opf_file = None
|
||||||
if self.db is not None:
|
if self.db is not None:
|
||||||
self.db.set_metadata(self.book_id, self.user_mi)
|
self.db.set_metadata(self.book_id, self.user_mi)
|
||||||
self.mi = self.db.get_metadata(self.book_id, index_is_id=True)
|
self.mi, self.opf_file = create_opf_file(self.db, self.book_id)
|
||||||
self.mi.application_id = uuid.uuid4()
|
|
||||||
opf = OPFCreator(os.getcwdu(), self.mi)
|
|
||||||
self.opf_file = PersistentTemporaryFile('.opf')
|
|
||||||
opf.render(self.opf_file)
|
|
||||||
self.opf_file.close()
|
|
||||||
if self.cover_changed and self.cover_data is not None:
|
if self.cover_changed and self.cover_data is not None:
|
||||||
self.db.set_cover(self.book_id, self.cover_data)
|
self.db.set_cover(self.book_id, self.cover_data)
|
||||||
cover = self.db.cover(self.book_id, index_is_id=True)
|
cover = self.db.cover(self.book_id, index_is_id=True)
|
||||||
|
@ -68,6 +68,36 @@ class GroupModel(QAbstractListModel):
|
|||||||
return QVariant(f)
|
return QVariant(f)
|
||||||
return NONE
|
return NONE
|
||||||
|
|
||||||
|
def get_preferred_input_format_for_book(db, book_id):
|
||||||
|
recs = load_specifics(db, book_id)
|
||||||
|
if recs:
|
||||||
|
return recs.get('gui_preferred_input_format', None)
|
||||||
|
|
||||||
|
def get_available_formats_for_book(db, book_id):
|
||||||
|
available_formats = db.formats(book_id, index_is_id=True)
|
||||||
|
if not available_formats:
|
||||||
|
available_formats = ''
|
||||||
|
return set([x.lower() for x in
|
||||||
|
available_formats.split(',')])
|
||||||
|
|
||||||
|
def get_supported_input_formats_for_book(db, book_id):
|
||||||
|
available_formats = get_available_formats_for_book(db, book_id)
|
||||||
|
input_formats = set([x.lower() for x in supported_input_formats()])
|
||||||
|
input_formats = sorted(available_formats.intersection(input_formats))
|
||||||
|
if not input_formats:
|
||||||
|
raise NoSupportedInputFormats
|
||||||
|
return input_formats
|
||||||
|
|
||||||
|
|
||||||
|
def get_input_format_for_book(db, book_id, pref):
|
||||||
|
if pref is None:
|
||||||
|
pref = get_preferred_input_format_for_book(db, book_id)
|
||||||
|
input_formats = get_supported_input_formats_for_book(db, book_id)
|
||||||
|
input_format = pref if pref in input_formats else \
|
||||||
|
sort_formats_by_preference(input_formats, prefs['input_format_order'])[0]
|
||||||
|
return input_format, input_formats
|
||||||
|
|
||||||
|
|
||||||
class Config(ResizableDialog, Ui_Dialog):
|
class Config(ResizableDialog, Ui_Dialog):
|
||||||
'''
|
'''
|
||||||
Configuration dialog for single book conversion. If accepted, has the
|
Configuration dialog for single book conversion. If accepted, has the
|
||||||
@ -86,12 +116,6 @@ class Config(ResizableDialog, Ui_Dialog):
|
|||||||
preferred_input_format=None, preferred_output_format=None):
|
preferred_input_format=None, preferred_output_format=None):
|
||||||
ResizableDialog.__init__(self, parent)
|
ResizableDialog.__init__(self, parent)
|
||||||
|
|
||||||
if preferred_input_format is None and db is not None:
|
|
||||||
recs = load_specifics(db, book_id)
|
|
||||||
if recs:
|
|
||||||
preferred_input_format = recs.get('gui_preferred_input_format',
|
|
||||||
None)
|
|
||||||
|
|
||||||
self.setup_input_output_formats(db, book_id, preferred_input_format,
|
self.setup_input_output_formats(db, book_id, preferred_input_format,
|
||||||
preferred_output_format)
|
preferred_output_format)
|
||||||
self.db, self.book_id = db, book_id
|
self.db, self.book_id = db, book_id
|
||||||
@ -194,22 +218,10 @@ class Config(ResizableDialog, Ui_Dialog):
|
|||||||
preferred_output_format):
|
preferred_output_format):
|
||||||
if preferred_output_format:
|
if preferred_output_format:
|
||||||
preferred_output_format = preferred_output_format.lower()
|
preferred_output_format = preferred_output_format.lower()
|
||||||
available_formats = db.formats(book_id, index_is_id=True)
|
|
||||||
if not available_formats:
|
|
||||||
available_formats = ''
|
|
||||||
available_formats = set([x.lower() for x in
|
|
||||||
available_formats.split(',')])
|
|
||||||
input_formats = set([x.lower() for x in supported_input_formats()])
|
|
||||||
input_formats = \
|
|
||||||
sorted(available_formats.intersection(input_formats))
|
|
||||||
if not input_formats:
|
|
||||||
raise NoSupportedInputFormats
|
|
||||||
output_formats = sorted(available_output_formats())
|
output_formats = sorted(available_output_formats())
|
||||||
output_formats.remove('oeb')
|
output_formats.remove('oeb')
|
||||||
preferred_input_format = preferred_input_format if \
|
input_format, input_formats = get_input_format_for_book(db, book_id,
|
||||||
preferred_input_format in input_formats else \
|
preferred_input_format)
|
||||||
sort_formats_by_preference(input_formats,
|
|
||||||
prefs['input_format_order'])[0]
|
|
||||||
preferred_output_format = preferred_output_format if \
|
preferred_output_format = preferred_output_format if \
|
||||||
preferred_output_format in output_formats else \
|
preferred_output_format in output_formats else \
|
||||||
sort_formats_by_preference(output_formats,
|
sort_formats_by_preference(output_formats,
|
||||||
@ -218,7 +230,7 @@ class Config(ResizableDialog, Ui_Dialog):
|
|||||||
input_formats])))
|
input_formats])))
|
||||||
self.output_formats.addItems(list(map(QString, [x.upper() for x in
|
self.output_formats.addItems(list(map(QString, [x.upper() for x in
|
||||||
output_formats])))
|
output_formats])))
|
||||||
self.input_formats.setCurrentIndex(input_formats.index(preferred_input_format))
|
self.input_formats.setCurrentIndex(input_formats.index(input_format))
|
||||||
self.output_formats.setCurrentIndex(output_formats.index(preferred_output_format))
|
self.output_formats.setCurrentIndex(output_formats.index(preferred_output_format))
|
||||||
|
|
||||||
def show_pane(self, index):
|
def show_pane(self, index):
|
||||||
|
@ -14,8 +14,10 @@ from PyQt4.Qt import QDialog
|
|||||||
from calibre.ptempfile import PersistentTemporaryFile
|
from calibre.ptempfile import PersistentTemporaryFile
|
||||||
from calibre.gui2 import warning_dialog, question_dialog
|
from calibre.gui2 import warning_dialog, question_dialog
|
||||||
from calibre.gui2.convert.single import NoSupportedInputFormats
|
from calibre.gui2.convert.single import NoSupportedInputFormats
|
||||||
from calibre.gui2.convert.single import Config as SingleConfig
|
from calibre.gui2.convert.single import Config as SingleConfig, \
|
||||||
|
get_input_format_for_book
|
||||||
from calibre.gui2.convert.bulk import BulkConfig
|
from calibre.gui2.convert.bulk import BulkConfig
|
||||||
|
from calibre.gui2.convert.metadata import create_opf_file, create_cover_file
|
||||||
from calibre.customize.conversion import OptionRecommendation
|
from calibre.customize.conversion import OptionRecommendation
|
||||||
from calibre.utils.config import prefs
|
from calibre.utils.config import prefs
|
||||||
from calibre.ebooks.conversion.config import GuiRecommendations, \
|
from calibre.ebooks.conversion.config import GuiRecommendations, \
|
||||||
@ -112,13 +114,11 @@ def convert_bulk_ebook(parent, db, book_ids, out_format=None):
|
|||||||
book_ids = convert_existing(parent, db, book_ids, output_format)
|
book_ids = convert_existing(parent, db, book_ids, output_format)
|
||||||
for i, book_id in enumerate(book_ids):
|
for i, book_id in enumerate(book_ids):
|
||||||
temp_files = []
|
temp_files = []
|
||||||
|
input_format = get_input_format_for_book(db, book_id, None)[0]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
d = SingleConfig(parent, db, book_id, None, output_format)
|
mi, opf_file = create_opf_file(db, book_id)
|
||||||
d.accept()
|
in_file = db.format_abspath(book_id, input_format, True)
|
||||||
|
|
||||||
mi = db.get_metadata(book_id, True)
|
|
||||||
in_file = db.format_abspath(book_id, d.input_format, True)
|
|
||||||
|
|
||||||
out_file = PersistentTemporaryFile('.' + output_format)
|
out_file = PersistentTemporaryFile('.' + output_format)
|
||||||
out_file.write(output_format)
|
out_file.write(output_format)
|
||||||
@ -126,7 +126,7 @@ def convert_bulk_ebook(parent, db, book_ids, out_format=None):
|
|||||||
temp_files = []
|
temp_files = []
|
||||||
|
|
||||||
combined_recs = GuiRecommendations()
|
combined_recs = GuiRecommendations()
|
||||||
default_recs = load_defaults('%s_input' % d.input_format)
|
default_recs = load_defaults('%s_input' % input_format)
|
||||||
specific_recs = load_specifics(db, book_id)
|
specific_recs = load_specifics(db, book_id)
|
||||||
for key in default_recs:
|
for key in default_recs:
|
||||||
combined_recs[key] = default_recs[key]
|
combined_recs[key] = default_recs[key]
|
||||||
@ -137,14 +137,16 @@ def convert_bulk_ebook(parent, db, book_ids, out_format=None):
|
|||||||
save_specifics(db, book_id, combined_recs)
|
save_specifics(db, book_id, combined_recs)
|
||||||
lrecs = list(combined_recs.to_recommendations())
|
lrecs = list(combined_recs.to_recommendations())
|
||||||
|
|
||||||
if d.opf_file is not None:
|
cover_file = create_cover_file(db, book_id)
|
||||||
lrecs.append(('read_metadata_from_opf', d.opf_file.name,
|
|
||||||
|
if opf_file is not None:
|
||||||
|
lrecs.append(('read_metadata_from_opf', opf_file.name,
|
||||||
OptionRecommendation.HIGH))
|
OptionRecommendation.HIGH))
|
||||||
temp_files.append(d.opf_file)
|
temp_files.append(opf_file)
|
||||||
if d.cover_file is not None:
|
if cover_file is not None:
|
||||||
lrecs.append(('cover', d.cover_file.name,
|
lrecs.append(('cover', cover_file.name,
|
||||||
OptionRecommendation.HIGH))
|
OptionRecommendation.HIGH))
|
||||||
temp_files.append(d.cover_file)
|
temp_files.append(cover_file)
|
||||||
|
|
||||||
for x in list(lrecs):
|
for x in list(lrecs):
|
||||||
if x[0] == 'debug_pipeline':
|
if x[0] == 'debug_pipeline':
|
||||||
@ -158,7 +160,7 @@ def convert_bulk_ebook(parent, db, book_ids, out_format=None):
|
|||||||
|
|
||||||
args = [in_file, out_file.name, lrecs]
|
args = [in_file, out_file.name, lrecs]
|
||||||
temp_files.append(out_file)
|
temp_files.append(out_file)
|
||||||
jobs.append(('gui_convert', args, desc, d.output_format.upper(), book_id, temp_files))
|
jobs.append(('gui_convert', args, desc, output_format.upper(), book_id, temp_files))
|
||||||
|
|
||||||
changed = True
|
changed = True
|
||||||
except NoSupportedInputFormats:
|
except NoSupportedInputFormats:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user