7
7
Logic for setting up conversion jobs
10
12
from PyQt4.Qt import QDialog
14
from calibre.ptempfile import PersistentTemporaryFile
15
from calibre.gui2 import warning_dialog
16
from calibre.gui2.convert.single import NoSupportedInputFormats
17
from calibre.gui2.convert.single import Config as SingleConfig
18
from calibre.gui2.convert.bulk import BulkConfig
19
from calibre.customize.conversion import OptionRecommendation
12
20
from calibre.utils.config import prefs
13
from calibre.gui2.dialogs.lrf_single import LRFSingleDialog, LRFBulkDialog
14
from calibre.gui2.dialogs.epub import Config as EPUBConvert
15
from calibre.gui2.dialogs.mobi import Config as MOBIConvert
16
import calibre.gui2.dialogs.comicconf as ComicConf
17
from calibre.gui2 import warning_dialog
18
from calibre.ptempfile import PersistentTemporaryFile
19
from calibre.ebooks.lrf import preferred_source_formats as LRF_PREFERRED_SOURCE_FORMATS
20
from calibre.ebooks.metadata.opf import OPFCreator
21
from calibre.ebooks.epub.from_any import SOURCE_FORMATS as EPUB_PREFERRED_SOURCE_FORMATS
29
def convert_single(fmt, parent, db, comics, others):
32
others_ids = [db.id(row) for row in others]
33
comics_ids = [db.id(row) for row in comics]
34
for row, row_id in zip(others, others_ids):
36
d = get_dialog(fmt)(parent, db, row)
37
if d.source_format is not None:
39
if d.result() == QDialog.Accepted:
41
data = db.format(row, d.source_format)
42
pt = PersistentTemporaryFile('.'+d.source_format.lower())
45
of = PersistentTemporaryFile('.'+fmt)
48
opts.from_opf = d.opf_file.name
50
args = [opts, pt.name]
52
temp_files.append(d.cover_file)
53
opts.cover = d.cover_file.name
54
temp_files.extend([d.opf_file, pt, of])
55
jobs.append(('any2'+fmt, args, _('Convert book: ')+d.mi.title,
56
fmt.upper(), row_id, temp_files))
59
for row, row_id in zip(comics, comics_ids):
60
mi = db.get_metadata(row)
61
title = author = _('Unknown')
65
author = ','.join(mi.authors)
66
defaults = db.conversion_options(db.id(row), 'comic')
67
opts, defaults = ComicConf.get_conversion_options(parent, defaults, title, author)
68
if defaults is not None:
69
db.set_conversion_options(db.id(row), 'comic', defaults)
70
if opts is None: continue
71
for _fmt in ['cbz', 'cbr']:
73
data = db.format(row, _fmt.upper())
78
pt = PersistentTemporaryFile('.'+_fmt)
81
of = PersistentTemporaryFile('.'+fmt)
85
args = [pt.name, opts]
87
jobs.append(('comic2'+fmt, args, _('Convert comic: ')+opts.title,
88
fmt.upper(), row_id, [pt, of]))
94
def convert_single_lrf(parent, db, comics, others):
97
others_ids = [db.id(row) for row in others]
98
comics_ids = [db.id(row) for row in comics]
99
for row, row_id in zip(others, others_ids):
101
d = LRFSingleDialog(parent, db, row)
102
if d.selected_format:
104
if d.result() == QDialog.Accepted:
106
data = db.format(row, d.selected_format)
107
pt = PersistentTemporaryFile('.'+d.selected_format.lower())
110
of = PersistentTemporaryFile('.lrf')
112
cmdline.extend(['-o', of.name])
113
cmdline.append(pt.name)
115
temp_files.append(d.cover_file)
116
temp_files.extend([pt, of])
117
jobs.append(('any2lrf', [cmdline], _('Convert book: ')+d.title(),
118
'LRF', row_id, temp_files))
121
for row, row_id in zip(comics, comics_ids):
122
mi = db.get_metadata(row)
123
title = author = _('Unknown')
127
author = ','.join(mi.authors)
128
defaults = db.conversion_options(db.id(row), 'comic')
129
opts, defaults = ComicConf.get_conversion_options(parent, defaults, title, author)
130
if defaults is not None:
131
db.set_conversion_options(db.id(row), 'comic', defaults)
132
if opts is None: continue
133
for fmt in ['cbz', 'cbr']:
135
data = db.format(row, fmt.upper())
142
pt = PersistentTemporaryFile('.'+fmt)
145
of = PersistentTemporaryFile('.lrf')
147
opts.output = of.name
149
args = [pt.name, opts]
151
jobs.append(('comic2lrf', args, _('Convert comic: ')+opts.title,
152
'LRF', row_id, [pt, of]))
156
def convert_bulk(fmt, parent, db, comics, others):
158
d = get_dialog(fmt)(parent, db)
159
if d.exec_() != QDialog.Accepted:
160
others, user_mi = [], None
166
comic_opts = ComicConf.get_bulk_conversion_options(parent)
171
total = sum(map(len, (others, comics)))
174
parent.status_bar.showMessage(_('Starting Bulk conversion of %d books')%total, 2000)
176
for i, row in enumerate(others+comics):
180
for _fmt in EPUB_PREFERRED_SOURCE_FORMATS:
182
data = db.format(row, _fmt.upper())
190
options = opts.copy()
191
mi = db.get_metadata(row)
192
if user_mi is not None:
193
if user_mi.series_index == 1:
194
user_mi.series_index = None
195
mi.smart_update(user_mi)
196
db.set_metadata(db.id(row), mi)
197
opf = OPFCreator(os.getcwdu(), mi)
198
opf_file = PersistentTemporaryFile('.opf')
201
pt = PersistentTemporaryFile('.'+_fmt.lower())
204
of = PersistentTemporaryFile('.'+fmt)
206
cover = db.cover(row)
209
cf = PersistentTemporaryFile('.jpeg')
212
options.cover = cf.name
213
options.output = of.name
214
options.from_opf = opf_file.name
215
args = [options, pt.name]
216
desc = _('Convert book %d of %d (%s)')%(i+1, total, repr(mi.title))
217
temp_files = [cf] if cf is not None else []
218
temp_files.extend([opf_file, pt, of])
219
jobs.append(('any2'+fmt, args, desc, fmt.upper(), row_id, temp_files))
221
options = comic_opts.copy()
222
mi = db.get_metadata(row)
224
options.title = mi.title
226
options.author = ','.join(mi.authors)
228
for _fmt in ['cbz', 'cbr']:
230
data = db.format(row, _fmt.upper())
236
pt = PersistentTemporaryFile('.'+_fmt.lower())
239
of = PersistentTemporaryFile('.'+fmt)
241
setattr(options, 'output', of.name)
243
args = [pt.name, options]
244
desc = _('Convert book %d of %d (%s)')%(i+1, total, repr(mi.title))
245
jobs.append(('comic2'+fmt, args, desc, fmt.upper(), row_id, [pt, of]))
250
title = db.title(row)
251
res.append('<li>%s</li>'%title)
253
msg = _('<p>Could not convert %d of %d books, because no suitable source format was found.<ul>%s</ul>')%(len(res), total, '\n'.join(res))
254
warning_dialog(parent, _('Could not convert some books'), msg).exec_()
259
def convert_bulk_lrf(parent, db, comics, others):
261
d = LRFBulkDialog(parent)
262
if d.exec_() != QDialog.Accepted:
265
comic_opts = ComicConf.get_bulk_conversion_options(parent)
270
total = sum(map(len, (others, comics)))
273
parent.status_bar.showMessage(_('Starting Bulk conversion of %d books')%total, 2000)
275
for i, row in enumerate(others+comics):
278
cmdline = list(d.cmdline)
279
mi = db.get_metadata(row)
281
cmdline.extend(['--title', mi.title])
283
cmdline.extend(['--author', ','.join(mi.authors)])
285
cmdline.extend(['--publisher', mi.publisher])
287
cmdline.extend(['--comment', mi.comments])
289
for fmt in LRF_PREFERRED_SOURCE_FORMATS:
291
data = db.format(row, fmt.upper())
299
pt = PersistentTemporaryFile('.'+fmt.lower())
302
of = PersistentTemporaryFile('.lrf')
304
cover = db.cover(row)
307
cf = PersistentTemporaryFile('.jpeg')
310
cmdline.extend(['--cover', cf.name])
311
cmdline.extend(['-o', of.name])
312
cmdline.append(pt.name)
313
desc = _('Convert book %d of %d (%s)')%(i+1, total, repr(mi.title))
314
temp_files = [cf] if cf is not None else []
315
temp_files.extend([pt, of])
316
jobs.append(('any2lrf', [cmdline], desc, 'LRF', row_id, temp_files))
318
options = comic_opts.copy()
319
mi = db.get_metadata(row)
321
options.title = mi.title
323
options.author = ','.join(mi.authors)
325
for fmt in ['cbz', 'cbr']:
327
data = db.format(row, fmt.upper())
333
pt = PersistentTemporaryFile('.'+fmt.lower())
336
of = PersistentTemporaryFile('.lrf')
338
setattr(options, 'output', of.name)
340
args = [pt.name, options]
341
desc = _('Convert book %d of %d (%s)')%(i+1, total, repr(mi.title))
342
jobs.append(('comic2lrf', args, desc, 'LRF', row_id, [pt, of]))
347
title = db.title(row)
348
res.append('<li>%s</li>'%title)
350
msg = _('<p>Could not convert %d of %d books, because no suitable source format was found.<ul>%s</ul>')%(len(res), total, '\n'.join(res))
351
warning_dialog(parent, _('Could not convert some books'), msg).exec_()
355
def set_conversion_defaults_lrf(comic, parent, db):
357
ComicConf.set_conversion_defaults(parent)
359
LRFSingleDialog(parent, None, None).exec_()
361
def _set_conversion_defaults(dialog, comic, parent, db):
363
ComicConf.set_conversion_defaults(parent)
365
d = dialog(parent, db)
366
d.setWindowTitle(_('Set conversion defaults'))
369
def _fetch_news(data, fmt):
370
pt = PersistentTemporaryFile(suffix='_feeds2%s.%s'%(fmt.lower(), fmt.lower()))
372
args = ['feeds2%s'%fmt.lower(), '--output', pt.name, '--debug']
374
args.extend(['--username', data['username']])
376
args.extend(['--password', data['password']])
377
args.append(data['script'] if data['script'] else data['title'])
378
return 'feeds2'+fmt.lower(), [args], _('Fetch news from ')+data['title'], fmt.upper(), [pt]
22
def convert_single_ebook(parent, db, book_ids, auto_conversion=False, out_format=None):
29
return None, None, None
30
parent.status_bar.showMessage(_('Starting conversion of %d books') % total, 2000)
32
for i, book_id in enumerate(book_ids):
36
d = SingleConfig(parent, db, book_id, None, out_format)
40
result = QDialog.Accepted
44
if result == QDialog.Accepted:
45
mi = db.get_metadata(book_id, True)
46
in_file = db.format_abspath(book_id, d.input_format, True)
48
out_file = PersistentTemporaryFile('.' + d.output_format)
49
out_file.write(d.output_format)
53
desc = _('Convert book %d of %d (%s)') % (i + 1, total, repr(mi.title))
55
recs = cPickle.loads(d.recommendations)
56
args = [in_file, out_file.name, recs]
57
if d.opf_file is not None:
58
recs.append(('read_metadata_from_opf', d.opf_file.name,
59
OptionRecommendation.HIGH))
60
temp_files.append(d.opf_file)
61
if d.cover_file is not None:
62
recs.append(('cover', d.cover_file.name,
63
OptionRecommendation.HIGH))
64
temp_files.append(d.cover_file)
65
temp_files.append(out_file)
66
jobs.append(('gui_convert', args, desc, d.output_format.upper(), book_id, temp_files))
69
except NoSupportedInputFormats:
75
title = db.title(id, True)
76
res.append('%s'%title)
78
msg = '%s' % '\n'.join(res)
79
warning_dialog(parent, _('Could not convert some books'),
80
_('Could not convert %d of %d books, because no suitable source'
81
' format was found.') % (len(res), total),
84
return jobs, changed, bad
86
def convert_bulk_ebook(parent, db, book_ids, out_format=None):
93
return None, None, None
94
parent.status_bar.showMessage(_('Starting conversion of %d books') % total, 2000)
96
d = BulkConfig(parent, db, out_format)
97
if d.exec_() != QDialog.Accepted:
98
return jobs, changed, bad
100
output_format = d.output_format
101
recs = cPickle.loads(d.recommendations)
103
for i, book_id in enumerate(book_ids):
107
d = SingleConfig(parent, db, book_id, None, output_format)
110
mi = db.get_metadata(book_id, True)
111
in_file = db.format_abspath(book_id, d.input_format, True)
113
out_file = PersistentTemporaryFile('.' + output_format)
114
out_file.write(output_format)
120
if d.opf_file is not None:
121
lrecs.append(('read_metadata_from_opf', d.opf_file.name,
122
OptionRecommendation.HIGH))
123
temp_files.append(d.opf_file)
124
if d.cover_file is not None:
125
lrecs.append(('cover', d.cover_file.name,
126
OptionRecommendation.HIGH))
127
temp_files.append(d.cover_file)
129
desc = _('Convert book %d of %d (%s)') % (i + 1, total, repr(mi.title))
131
args = [in_file, out_file.name, lrecs]
132
temp_files.append(out_file)
133
jobs.append(('gui_convert', args, desc, d.output_format.upper(), book_id, temp_files))
136
except NoSupportedInputFormats:
142
title = db.title(id, True)
143
res.append('%s'%title)
145
msg = '%s' % '\n'.join(res)
146
warning_dialog(parent, _('Could not convert some books'),
147
_('Could not convert %d of %d books, because no suitable '
148
'source format was found.') % (len(res), total),
151
return jobs, changed, bad
381
153
def fetch_scheduled_recipe(recipe, script):
382
154
from calibre.gui2.dialogs.scheduler import config
155
from calibre.ebooks.conversion.config import load_defaults
383
156
fmt = prefs['output_format'].lower()
384
pt = PersistentTemporaryFile(suffix='_feeds2%s.%s'%(fmt.lower(), fmt.lower()))
157
pt = PersistentTemporaryFile(suffix='_recipe_out.%s'%fmt.lower())
386
args = ['feeds2%s'%fmt.lower(), '--output', pt.name, '--debug']
160
ps = load_defaults('page_setup')
161
if 'output_profile' in ps:
162
recs.append(('output_profile', ps['output_profile'],
163
OptionRecommendation.HIGH))
164
lf = load_defaults('look_and_feel')
165
if lf.get('base_font_size', 0.0) != 0.0:
166
recs.append(('base_font_size', lf['base_font_size'],
167
OptionRecommendation.HIGH))
169
lr = load_defaults('lrf_output')
170
if lr.get('header', False):
171
recs.append(('header', True, OptionRecommendation.HIGH))
172
recs.append(('header_format', '%t', OptionRecommendation.HIGH))
174
args = [script, pt.name, recs]
387
175
if recipe.needs_subscription:
388
176
x = config.get('recipe_account_info_%s'%recipe.id, False)
390
178
raise ValueError(_('You must set a username and password for %s')%recipe.title)
391
args.extend(['--username', x[0], '--password', x[1]])
393
return 'feeds2'+fmt, [args], _('Fetch news from ')+recipe.title, fmt.upper(), [pt]
396
def convert_single_ebook(*args):
397
fmt = prefs['output_format'].lower()
399
return convert_single_lrf(*args)
400
elif fmt in ('epub', 'mobi'):
401
return convert_single(fmt, *args)
403
def convert_bulk_ebooks(*args):
404
fmt = prefs['output_format'].lower()
406
return convert_bulk_lrf(*args)
407
elif fmt in ('epub', 'mobi'):
408
return convert_bulk(fmt, *args)
410
def set_conversion_defaults(comic, parent, db):
411
fmt = prefs['output_format'].lower()
413
return set_conversion_defaults_lrf(comic, parent, db)
414
elif fmt in ('epub', 'mobi'):
415
return _set_conversion_defaults(get_dialog(fmt), comic, parent, db)
417
def fetch_news(data):
418
fmt = prefs['output_format'].lower()
419
return _fetch_news(data, fmt)
179
recs.append(('username', x[0], OptionRecommendation.HIGH))
180
recs.append(('password', x[1], OptionRecommendation.HIGH))
183
return 'gui_convert', args, _('Fetch news from ')+recipe.title, fmt.upper(), [pt]