IGN:Clean up conversion queueing code and add feedback while calibre is queueing bulk conversions

This commit is contained in:
Kovid Goyal 2009-09-13 10:27:36 -06:00
parent a1b42542e1
commit b52620748e
3 changed files with 198 additions and 231 deletions

View File

@ -1155,16 +1155,8 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
self.library_view.selectionModel().selectedRows()]
jobs, changed, bad = convert_single_ebook(self, self.library_view.model().db, book_ids, True, format)
if jobs == []: return
for func, args, desc, fmt, id, temp_files in jobs:
if id not in bad:
job = self.job_manager.run_job(Dispatcher(self.book_auto_converted),
func, args=args, description=desc)
self.conversion_jobs[job] = (temp_files, fmt, id, on_card)
if changed:
self.library_view.model().refresh_rows(rows)
current = self.library_view.currentIndex()
self.library_view.model().current_changed(current, previous)
self.queue_convert_jobs(jobs, changed, bad, rows, previous,
self.book_auto_converted, extra_job_args=[on_card])
def auto_convert_mail(self, to, fmts, delete_from_library, book_ids, format):
previous = self.library_view.currentIndex()
@ -1172,17 +1164,9 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
self.library_view.selectionModel().selectedRows()]
jobs, changed, bad = convert_single_ebook(self, self.library_view.model().db, book_ids, True, format)
if jobs == []: return
for func, args, desc, fmt, id, temp_files in jobs:
if id not in bad:
job = self.job_manager.run_job(Dispatcher(self.book_auto_converted_mail),
func, args=args, description=desc)
self.conversion_jobs[job] = (temp_files, fmt, id,
delete_from_library, to, fmts)
if changed:
self.library_view.model().refresh_rows(rows)
current = self.library_view.currentIndex()
self.library_view.model().current_changed(current, previous)
self.queue_convert_jobs(jobs, changed, bad, rows, previous,
self.book_auto_converted_mail,
extra_job_args=[delete_from_library, to, fmts])
def auto_convert_news(self, book_ids, format):
previous = self.library_view.currentIndex()
@ -1190,17 +1174,8 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
self.library_view.selectionModel().selectedRows()]
jobs, changed, bad = convert_single_ebook(self, self.library_view.model().db, book_ids, True, format)
if jobs == []: return
for func, args, desc, fmt, id, temp_files in jobs:
if id not in bad:
job = self.job_manager.run_job(Dispatcher(self.book_auto_converted_news),
func, args=args, description=desc)
self.conversion_jobs[job] = (temp_files, fmt, id)
if changed:
self.library_view.model().refresh_rows(rows)
current = self.library_view.currentIndex()
self.library_view.model().current_changed(current, previous)
self.queue_convert_jobs(jobs, changed, bad, rows, previous,
self.book_auto_converted_news)
def get_books_for_conversion(self):
rows = [r.row() for r in \
@ -1219,16 +1194,24 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
rows = [x.row() for x in \
self.library_view.selectionModel().selectedRows()]
if bulk or (bulk is None and len(book_ids) > 1):
jobs, changed, bad = convert_bulk_ebook(self,
self.library_view.model().db, book_ids, out_format=prefs['output_format'])
self.__bulk_queue = convert_bulk_ebook(self, self.queue_convert_jobs,
self.library_view.model().db, book_ids,
out_format=prefs['output_format'], args=(rows, previous,
self.book_converted))
else:
jobs, changed, bad = convert_single_ebook(self,
self.library_view.model().db, book_ids, out_format=prefs['output_format'])
self.queue_convert_jobs(jobs, changed, bad, rows, previous,
self.book_converted)
def queue_convert_jobs(self, jobs, changed, bad, rows, previous,
converted_func, extra_job_args=[]):
for func, args, desc, fmt, id, temp_files in jobs:
if id not in bad:
job = self.job_manager.run_job(Dispatcher(self.book_converted),
job = self.job_manager.run_job(Dispatcher(converted_func),
func, args=args, description=desc)
self.conversion_jobs[job] = (temp_files, fmt, id)
args = [temp_files, fmt, id]+extra_job_args
self.conversion_jobs[job] = tuple(args)
if changed:
self.library_view.model().refresh_rows(rows)
@ -1236,77 +1219,22 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
self.library_view.model().current_changed(current, previous)
def book_auto_converted(self, job):
temp_files, fmt, book_id, on_card = self.conversion_jobs.pop(job)
try:
if job.failed:
return self.job_exception(job)
data = open(temp_files[-1].name, 'rb')
self.library_view.model().db.add_format(book_id, fmt, data, index_is_id=True)
data.close()
self.status_bar.showMessage(job.description + (' completed'), 2000)
finally:
for f in temp_files:
try:
if os.path.exists(f.name):
os.remove(f.name)
except:
pass
self.tags_view.recount()
if self.current_view() is self.library_view:
current = self.library_view.currentIndex()
self.library_view.model().current_changed(current, QModelIndex())
temp_files, fmt, book_id, on_card = self.conversion_jobs[job]
self.book_converted(job)
self.sync_to_device(on_card, False, specific_format=fmt, send_ids=[book_id], do_auto_convert=False)
def book_auto_converted_mail(self, job):
temp_files, fmt, book_id, delete_from_library, to, fmts = self.conversion_jobs.pop(job)
try:
if job.failed:
self.job_exception(job)
return
data = open(temp_files[-1].name, 'rb')
self.library_view.model().db.add_format(book_id, fmt, data, index_is_id=True)
data.close()
self.status_bar.showMessage(job.description + (' completed'), 2000)
finally:
for f in temp_files:
try:
if os.path.exists(f.name):
os.remove(f.name)
except:
pass
self.tags_view.recount()
if self.current_view() is self.library_view:
current = self.library_view.currentIndex()
self.library_view.model().current_changed(current, QModelIndex())
temp_files, fmt, book_id, delete_from_library, to, fmts = self.conversion_jobs[job]
self.book_converted(job)
self.send_by_mail(to, fmts, delete_from_library, specific_format=fmt, send_ids=[book_id], do_auto_convert=False)
def book_auto_converted_news(self, job):
temp_files, fmt, book_id = self.conversion_jobs.pop(job)
try:
if job.failed:
return self.job_exception(job)
data = open(temp_files[-1].name, 'rb')
self.library_view.model().db.add_format(book_id, fmt, data, index_is_id=True)
data.close()
self.status_bar.showMessage(job.description + (' completed'), 2000)
finally:
for f in temp_files:
try:
if os.path.exists(f.name):
os.remove(f.name)
except:
pass
self.tags_view.recount()
if self.current_view() is self.library_view:
current = self.library_view.currentIndex()
self.library_view.model().current_changed(current, QModelIndex())
temp_files, fmt, book_id = self.conversion_jobs[job]
self.book_converted(job)
self.sync_news(send_ids=[book_id], do_auto_convert=False)
def book_converted(self, job):
temp_files, fmt, book_id = self.conversion_jobs.pop(job)
temp_files, fmt, book_id = self.conversion_jobs.pop(job)[:3]
try:
if job.failed:
self.job_exception(job)

View File

@ -9,7 +9,7 @@ Logic for setting up conversion jobs
import cPickle
from PyQt4.Qt import QDialog
from PyQt4.Qt import QDialog, QProgressDialog, QString, QTimer, SIGNAL
from calibre.ptempfile import PersistentTemporaryFile
from calibre.gui2 import warning_dialog, question_dialog
@ -94,7 +94,7 @@ def convert_single_ebook(parent, db, book_ids, auto_conversion=False, out_format
return jobs, changed, bad
def convert_bulk_ebook(parent, db, book_ids, out_format=None):
def convert_bulk_ebook(parent, queue, db, book_ids, out_format=None, args=[]):
changed = False
jobs = []
bad = []
@ -112,32 +112,55 @@ def convert_bulk_ebook(parent, db, book_ids, out_format=None):
user_recs = cPickle.loads(d.recommendations)
book_ids = convert_existing(parent, db, book_ids, output_format)
for i, book_id in enumerate(book_ids):
return QueueBulk(parent, book_ids, output_format, queue, db, user_recs, args)
class QueueBulk(QProgressDialog):
def __init__(self, parent, book_ids, output_format, queue, db, user_recs, args):
QProgressDialog.__init__(self, '',
QString(), 0, len(book_ids), parent)
self.setWindowTitle(_('Queueing books for bulk conversion'))
self.book_ids, self.output_format, self.queue, self.db, self.args, self.user_recs = \
book_ids, output_format, queue, db, args, user_recs
self.parent = parent
self.i, self.bad, self.jobs, self.changed = 0, [], [], False
self.timer = QTimer(self)
self.connect(self.timer, SIGNAL('timeout()'), self.do_book)
self.timer.start()
self.exec_()
def do_book(self):
if self.i >= len(self.book_ids):
self.timer.stop()
return self.do_queue()
book_id = self.book_ids[self.i]
self.i += 1
temp_files = []
input_format = get_input_format_for_book(db, book_id, None)[0]
try:
mi, opf_file = create_opf_file(db, book_id)
in_file = db.format_abspath(book_id, input_format, True)
input_format = get_input_format_for_book(self.db, book_id, None)[0]
mi, opf_file = create_opf_file(self.db, book_id)
in_file = self.db.format_abspath(book_id, input_format, True)
out_file = PersistentTemporaryFile('.' + output_format)
out_file.write(output_format)
out_file = PersistentTemporaryFile('.' + self.output_format)
out_file.write(self.output_format)
out_file.close()
temp_files = []
combined_recs = GuiRecommendations()
default_recs = load_defaults('%s_input' % input_format)
specific_recs = load_specifics(db, book_id)
specific_recs = load_specifics(self.db, book_id)
for key in default_recs:
combined_recs[key] = default_recs[key]
for key in specific_recs:
combined_recs[key] = specific_recs[key]
for item in user_recs:
for item in self.user_recs:
combined_recs[item[0]] = item[1]
save_specifics(db, book_id, combined_recs)
save_specifics(self.db, book_id, combined_recs)
lrecs = list(combined_recs.to_recommendations())
cover_file = create_cover_file(db, book_id)
cover_file = create_cover_file(self.db, book_id)
if opf_file is not None:
lrecs.append(('read_metadata_from_opf', opf_file.name,
@ -156,30 +179,34 @@ def convert_bulk_ebook(parent, db, book_ids, out_format=None):
dtitle = unicode(mi.title)
except:
dtitle = repr(mi.title)
desc = _('Convert book %d of %d (%s)') % (i + 1, total, dtitle)
self.setLabelText(_('Queueing ')+dtitle)
desc = _('Convert book %d of %d (%s)') % (self.i, len(self.book_ids), dtitle)
args = [in_file, out_file.name, lrecs]
temp_files.append(out_file)
jobs.append(('gui_convert', args, desc, output_format.upper(), book_id, temp_files))
self.jobs.append(('gui_convert', args, desc, self.output_format.upper(), book_id, temp_files))
changed = True
self.changed = True
self.setValue(self.i)
except NoSupportedInputFormats:
bad.append(book_id)
self.bad.append(book_id)
if bad != []:
def do_queue(self):
self.hide()
if self.bad != []:
res = []
for id in bad:
title = db.title(id, True)
for id in self.bad:
title = self.db.title(id, True)
res.append('%s'%title)
msg = '%s' % '\n'.join(res)
warning_dialog(parent, _('Could not convert some books'),
warning_dialog(self.parent, _('Could not convert some books'),
_('Could not convert %d of %d books, because no suitable '
'source format was found.') % (len(res), total),
'source format was found.') % (len(res), len(self.book_ids)),
msg).exec_()
jobs.reverse()
return jobs, changed, bad
self.parent = None
self.jobs.reverse()
self.queue(self.jobs, self.changed, self.bad, *self.args)
def fetch_scheduled_recipe(recipe, script):
from calibre.gui2.dialogs.scheduler import config

View File

@ -5,8 +5,8 @@
msgid ""
msgstr ""
"Project-Id-Version: calibre 0.6.12\n"
"POT-Creation-Date: 2009-09-11 15:00+MDT\n"
"PO-Revision-Date: 2009-09-11 15:00+MDT\n"
"POT-Creation-Date: 2009-09-13 10:26+MDT\n"
"PO-Revision-Date: 2009-09-13 10:26+MDT\n"
"Last-Translator: Automatically generated\n"
"Language-Team: LANGUAGE\n"
"MIME-Version: 1.0\n"
@ -29,8 +29,8 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/comic/input.py:403
#: /home/kovid/work/calibre/src/calibre/ebooks/fb2/input.py:65
#: /home/kovid/work/calibre/src/calibre/ebooks/fb2/input.py:67
#: /home/kovid/work/calibre/src/calibre/ebooks/html/input.py:317
#: /home/kovid/work/calibre/src/calibre/ebooks/html/input.py:320
#: /home/kovid/work/calibre/src/calibre/ebooks/html/input.py:318
#: /home/kovid/work/calibre/src/calibre/ebooks/html/input.py:321
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1895
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/html/convert_from.py:1897
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/output.py:24
@ -99,9 +99,9 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/add.py:111
#: /home/kovid/work/calibre/src/calibre/gui2/add.py:118
#: /home/kovid/work/calibre/src/calibre/gui2/convert/__init__.py:21
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:81
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:106
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:108
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:99
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:124
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:126
#: /home/kovid/work/calibre/src/calibre/gui2/device.py:539
#: /home/kovid/work/calibre/src/calibre/gui2/device.py:548
#: /home/kovid/work/calibre/src/calibre/gui2/device.py:765
@ -976,7 +976,7 @@ msgid "Normally this input plugin re-arranges all the input files into a standar
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/html/input.py:266
msgid "Average line length for line breaking if the HTML is from a previous partial conversion of a PDF file. Default is %default."
msgid "Average line length for line breaking if the HTML is from a previous partial conversion of a PDF file. Default is %default which disables this."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/ebooks/lit/from_any.py:47
@ -2001,7 +2001,7 @@ msgid "Bulk Convert"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/bulk.py:73
#: /home/kovid/work/calibre/src/calibre/gui2/convert/single.py:153
#: /home/kovid/work/calibre/src/calibre/gui2/convert/single.py:177
msgid "Options specific to the output format."
msgstr ""
@ -2339,43 +2339,43 @@ msgstr ""
msgid "&Monospaced font family:"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:23
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:41
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main.py:145
#: /home/kovid/work/calibre/src/calibre/gui2/viewer/main_ui.py:169
msgid "Metadata"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:25
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:43
msgid "Set the metadata. The output file will contain as much of this metadata as possible."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:134
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:152
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:95
msgid "Choose cover for "
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:141
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:159
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:102
msgid "Cannot read"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:142
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:160
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:103
msgid "You do not have permission to read the file: "
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:150
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:157
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:168
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:175
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:111
msgid "Error reading file"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:151
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:169
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:112
msgid "<p>There was an error reading from file: <br /><b>"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:158
#: /home/kovid/work/calibre/src/calibre/gui2/convert/metadata.py:176
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:120
msgid " is not a valid picture"
msgstr ""
@ -2571,7 +2571,7 @@ msgid "RB Output"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/regex_builder.py:76
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1385
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1313
msgid "Choose the format to view"
msgstr ""
@ -2603,11 +2603,11 @@ msgstr ""
msgid "Regex:"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/single.py:139
#: /home/kovid/work/calibre/src/calibre/gui2/convert/single.py:163
msgid "Convert"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/convert/single.py:164
#: /home/kovid/work/calibre/src/calibre/gui2/convert/single.py:188
msgid "Options specific to the input format."
msgstr ""
@ -2860,7 +2860,7 @@ msgid "<p>For example, to match all h2 tags that have class=\"chapter\", set tag
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/device.py:39
#: /home/kovid/work/calibre/src/calibre/utils/ipc/job.py:129
#: /home/kovid/work/calibre/src/calibre/utils/ipc/job.py:130
msgid "No details available."
msgstr ""
@ -3184,7 +3184,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config/__init__.py:788
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:140
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1004
#: /home/kovid/work/calibre/src/calibre/utils/ipc/job.py:52
#: /home/kovid/work/calibre/src/calibre/utils/ipc/job.py:53
msgid "Error"
msgstr ""
@ -3712,18 +3712,22 @@ msgstr ""
msgid "Details of job"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/jobs_ui.py:41
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/jobs_ui.py:44
msgid "Active Jobs"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/jobs_ui.py:42
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/jobs_ui.py:45
msgid "&Stop selected job"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/jobs_ui.py:43
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/jobs_ui.py:46
msgid "Show job &details"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/jobs_ui.py:47
msgid "Stop &all jobs"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:133
msgid "Edit Meta information"
msgstr ""
@ -4474,11 +4478,11 @@ msgstr ""
msgid "Job has already run"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/jobs.py:215
#: /home/kovid/work/calibre/src/calibre/gui2/jobs.py:221
msgid "Unavailable"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/jobs.py:226
#: /home/kovid/work/calibre/src/calibre/gui2/jobs.py:232
msgid " - Jobs"
msgstr ""
@ -4673,7 +4677,7 @@ msgid "Save to disk in a single directory"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:280
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1487
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1415
msgid "Save only %s format to disk"
msgstr ""
@ -4713,7 +4717,7 @@ msgid "Calibre Library"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:437
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1630
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1558
msgid "Choose a location for your ebook library."
msgstr ""
@ -4817,7 +4821,7 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1015
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1048
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1073
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1210
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1185
msgid "No books selected"
msgstr ""
@ -4883,162 +4887,162 @@ msgstr ""
msgid " fetched."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1209
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1184
msgid "Cannot convert"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1379
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1398
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1307
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1326
msgid "No book selected"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1379
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1429
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1307
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1357
msgid "Cannot view"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1397
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1325
msgid "Cannot open folder"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1414
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1342
msgid "Multiple Books Selected"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1415
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1343
msgid "You are attempting to open %d books. Opening too many books at once can be slow and have a negative effect on the responsiveness of your computer. Once started the process cannot be stopped until complete. Do you wish to continue?"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1430
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1358
msgid "%s has no available formats."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1471
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1399
msgid "Cannot configure"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1472
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1400
msgid "Cannot configure while there are running jobs."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1515
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1443
msgid "No detailed info available"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1516
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1444
msgid "No detailed information is available for books on the device."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1568
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1496
msgid "Error talking to device"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1569
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1497
msgid "There was a temporary error talking to the device. Please unplug and reconnect the device and or reboot."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1592
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1610
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1520
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1538
msgid "Conversion Error"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1593
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1521
msgid "<p>Could not convert: %s<p>It is a <a href=\"%s\">DRM</a>ed book. You must first remove the DRM using third party tools."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1611
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1539
msgid "<b>Failed</b>"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1639
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1567
msgid "Invalid library location"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1640
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1568
msgid "Could not access %s. Using %s as the library."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1687
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1615
msgid "is the result of the efforts of many volunteers from all over the world. If you find it useful, please consider donating to support its development."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1711
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1639
msgid "There are active jobs. Are you sure you want to quit?"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1714
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1642
msgid ""
" is communicating with the device!<br>\n"
" Quitting may cause corruption on the device.<br>\n"
" Are you sure you want to quit?"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1718
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1646
msgid "WARNING: Active jobs"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1769
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1697
msgid "will keep running in the system tray. To close it, choose <b>Quit</b> in the context menu of the system tray."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1788
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1716
msgid "<span style=\"color:red; font-weight:bold\">Latest version: <a href=\"%s\">%s</a></span>"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1796
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1724
msgid "Update available"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1797
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1725
msgid "%s has been updated to version %s. See the <a href=\"http://calibre.kovidgoyal.net/wiki/Changelog\">new features</a>. Visit the download page?"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1815
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1743
msgid "Use the library located at the specified path."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1817
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1745
msgid "Start minimized to system tray."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1819
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1747
msgid "Log debugging information to console"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1821
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1749
msgid "Do not check for updates"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1869
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1797
msgid "If you are sure it is not running"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1871
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1799
msgid "Cannot Start "
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1872
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1800
msgid "%s is already running."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1875
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1803
msgid "may be running in the system tray, in the"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1877
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1805
msgid "upper right region of the screen."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1879
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1807
msgid "lower right region of the screen."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1882
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1810
msgid "try rebooting your computer."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1884
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1896
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1812
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1824
msgid "try deleting the file"
msgstr ""
@ -5224,39 +5228,47 @@ msgstr ""
msgid "Publishers"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:32
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:103
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:34
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:105
msgid "Starting conversion of %d books"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:62
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:153
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:64
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:183
msgid "Convert book %d of %d (%s)"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:88
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:170
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:90
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:203
msgid "Could not convert some books"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:89
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:171
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:91
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:204
msgid "Could not convert %d of %d books, because no suitable source format was found."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:202
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:122
msgid "Queueing books for bulk conversion"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:182
msgid "Queueing "
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:236
msgid "You must set a username and password for %s"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:207
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:241
msgid "Fetch news from "
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:218
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:252
msgid "Convert existing"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:219
#: /home/kovid/work/calibre/src/calibre/gui2/tools.py:253
msgid "The following books have already been converted to %s format. Do you wish to reconvert them?"
msgstr ""
@ -6235,72 +6247,72 @@ msgid ""
"Start the calibre content server."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/utils/config.py:43
#: /home/kovid/work/calibre/src/calibre/utils/config.py:45
msgid ""
"%sUsage%s: %s\n"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/utils/config.py:87
#: /home/kovid/work/calibre/src/calibre/utils/config.py:89
msgid "Created by "
msgstr ""
#: /home/kovid/work/calibre/src/calibre/utils/config.py:88
#: /home/kovid/work/calibre/src/calibre/utils/config.py:90
msgid "Whenever you pass arguments to %prog that have spaces in them, enclose the arguments in quotation marks."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/utils/config.py:551
#: /home/kovid/work/calibre/src/calibre/utils/config.py:553
msgid "Path to the database in which books are stored"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/utils/config.py:553
#: /home/kovid/work/calibre/src/calibre/utils/config.py:555
msgid "Pattern to guess metadata from filenames"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/utils/config.py:555
#: /home/kovid/work/calibre/src/calibre/utils/config.py:557
msgid "Access key for isbndb.com"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/utils/config.py:557
#: /home/kovid/work/calibre/src/calibre/utils/config.py:559
msgid "Default timeout for network operations (seconds)"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/utils/config.py:559
#: /home/kovid/work/calibre/src/calibre/utils/config.py:561
msgid "Path to directory in which your library of books is stored"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/utils/config.py:561
#: /home/kovid/work/calibre/src/calibre/utils/config.py:563
msgid "The language in which to display the user interface"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/utils/config.py:563
#: /home/kovid/work/calibre/src/calibre/utils/config.py:565
msgid "The default output format for ebook conversions."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/utils/config.py:567
#: /home/kovid/work/calibre/src/calibre/utils/config.py:569
msgid "Ordered list of formats to prefer for input."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/utils/config.py:569
#: /home/kovid/work/calibre/src/calibre/utils/config.py:571
msgid "Read metadata from files"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/utils/config.py:571
#: /home/kovid/work/calibre/src/calibre/utils/config.py:573
msgid "The priority of worker processes"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/utils/ipc/job.py:42
#: /home/kovid/work/calibre/src/calibre/utils/ipc/job.py:43
msgid "Waiting..."
msgstr ""
#: /home/kovid/work/calibre/src/calibre/utils/ipc/job.py:50
#: /home/kovid/work/calibre/src/calibre/utils/ipc/job.py:51
msgid "Stopped"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/utils/ipc/job.py:52
#: /home/kovid/work/calibre/src/calibre/utils/ipc/job.py:53
msgid "Finished"
msgstr ""
#: /home/kovid/work/calibre/src/calibre/utils/ipc/job.py:69
#: /home/kovid/work/calibre/src/calibre/utils/ipc/job.py:70
msgid "Working..."
msgstr ""
@ -6471,12 +6483,12 @@ msgid "sr-Latn-RS"
msgstr ""
#:
#: /home/kovid/work/calibre/src/calibre/web/feeds/recipes/recipe_le_monde.py:81
#: /home/kovid/work/calibre/src/calibre/web/feeds/recipes/recipe_le_monde.py:108
msgid "Skipping duplicated article: %s"
msgstr ""
#:
#: /home/kovid/work/calibre/src/calibre/web/feeds/recipes/recipe_le_monde.py:86
#: /home/kovid/work/calibre/src/calibre/web/feeds/recipes/recipe_le_monde.py:113
msgid "Skipping filtered article: %s"
msgstr ""