In-server conversion basically works, phew!

Now to create the UI for conversion settings.
This commit is contained in:
Kovid Goyal 2018-06-30 08:18:27 +05:30
parent 256c509238
commit 72fbe75bec
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
4 changed files with 34 additions and 22 deletions

View File

@ -20,7 +20,7 @@ from calibre.customize.ui import run_plugins_on_import, run_plugins_on_postimpor
from calibre.db import SPOOL_SIZE, _get_next_series_num_for_list
from calibre.db.categories import get_categories
from calibre.db.locking import create_locks, DowngradeLockError, SafeReadLock
from calibre.db.errors import NoSuchFormat
from calibre.db.errors import NoSuchFormat, NoSuchBook
from calibre.db.fields import create_field, IDENTITY, InvalidLinkTable
from calibre.db.search import Search
from calibre.db.tables import VirtualTable
@ -1340,10 +1340,9 @@ class Cache(object):
user_mi = mi.get_all_user_metadata(make_copy=False)
fm = self.field_metadata
for key in user_mi.iterkeys():
if (key in fm and
user_mi[key]['datatype'] == fm[key]['datatype'] and
(user_mi[key]['datatype'] != 'text' or
user_mi[key]['is_multiple'] == fm[key]['is_multiple'])):
if (key in fm and user_mi[key]['datatype'] == fm[key]['datatype'] and (
user_mi[key]['datatype'] != 'text' or (
user_mi[key]['is_multiple'] == fm[key]['is_multiple']))):
val = mi.get(key, None)
if force_changes or val is not None:
protected_set_field(key, val)
@ -1397,6 +1396,8 @@ class Cache(object):
fmt = check_ebook_format(stream_or_path, fmt)
with self.write_lock:
if not self._has_id(book_id):
raise NoSuchBook(book_id)
fmt = (fmt or '').upper()
self.format_metadata_cache[book_id].pop(fmt, None)
try:

View File

@ -11,3 +11,9 @@ __docformat__ = 'restructuredtext en'
class NoSuchFormat(ValueError):
pass
class NoSuchBook(KeyError):
def __init__(self, book_id):
KeyError.__init__(self, 'No book with id: {} in database'.format(book_id))
self.book_id = book_id

View File

@ -9,6 +9,7 @@ import shutil
import tempfile
from threading import Lock
from calibre.db.errors import NoSuchBook
from calibre.srv.changes import formats_added
from calibre.srv.errors import BookNotFound, HTTPNotFound
from calibre.srv.routes import endpoint, json
@ -25,7 +26,7 @@ class JobStatus(object):
def __init__(self, job_id, book_id, tdir, library_id, pathtoebook, conversion_data):
self.job_id = job_id
self.log = ''
self.log = self.traceback = ''
self.book_id = book_id
self.output_path = os.path.join(
tdir, 'output.' + conversion_data['output_fmt'].lower())
@ -34,9 +35,11 @@ class JobStatus(object):
self.conversion_data = conversion_data
self.running = self.ok = True
self.last_check_at = monotonic()
self.was_aborted = False
def cleanup(self):
safe_delete_tree(self.tdir)
self.log = self.traceback = ''
@property
def current_status(self):
@ -106,7 +109,7 @@ def convert_book(path_to_ebook, opf_path, cover_path, output_fmt, recs):
os.chdir(os.path.dirname(path_to_ebook))
status_file = share_open('status', 'wb')
def notification(percent, msg):
def notification(percent, msg=''):
status_file.write('{}:{}|||\n'.format(percent, msg).encode('utf-8'))
status_file.flush()
@ -129,11 +132,11 @@ def queue_job(ctx, rd, library_id, db, fmt, book_id, conversion_data):
fd, pathtocover = tempfile.mkstemp(prefix='', suffix=('.jpg'), dir=tdir)
with os.fdopen(fd, 'wb') as f:
cover_copied = db.copy_cover_to(book_id, f)
cover_path = f.name if cover_copied else None
cover_path = pathtocover if cover_copied else None
mi = db.get_metadata(book_id)
mi.application_id = mi.uuid
raw = metadata_to_opf(mi)
fd, pathtocover = tempfile.mkstemp(prefix='', suffix=('.opf'), dir=tdir)
fd, opf_path = tempfile.mkstemp(prefix='', suffix=('.opf'), dir=tdir)
with os.fdopen(fd, 'wb') as metadata_file:
metadata_file.write(raw)
@ -146,7 +149,7 @@ def queue_job(ctx, rd, library_id, db, fmt, book_id, conversion_data):
job_id = ctx.start_job(
'Convert book %s (%s)' % (book_id, fmt), 'calibre.srv.convert',
'convert_book', args=(
pathtoebook, metadata_file.name, cover_path, conversion_data['output_fmt'], recs),
pathtoebook, opf_path, cover_path, conversion_data['output_fmt'], recs),
job_done_callback=job_done
)
expire_old_jobs()
@ -181,19 +184,20 @@ def conversion_status(ctx, rd, job_id):
del conversion_jobs[job_id]
try:
ans = {'running': False, 'ok': job_status.ok, 'was_aborted': job_status.was_aborted,
'traceback': job_status.traceback, 'log': job_status.log}
ans = {'running': False, 'ok': job_status.ok, 'was_aborted':
job_status.was_aborted, 'traceback': job_status.traceback,
'log': job_status.log}
if job_status.ok:
db, library_id = get_library_data(ctx, rd)[:2]
if library_id != job_status.library_id:
raise HTTPNotFound('job library_id does not match')
with db.safe_read_lock:
if not db.has_id(job_status.book_id):
raise HTTPNotFound(
'book_id {} not found in library'.format(job_status.book_id))
fmt = job_status.output_path.rpartition('.')[-1]
fmt = job_status.output_path.rpartition('.')[-1]
try:
db.add_format(job_status.book_id, fmt, job_status.output_path)
formats_added({job_status.book_id: (fmt,)})
except NoSuchBook:
raise HTTPNotFound(
'book_id {} not found in library'.format(job_status.book_id))
formats_added({job_status.book_id: (fmt,)})
ans['size'] = os.path.getsize(job_status.output_path)
ans['fmt'] = fmt
return ans

View File

@ -66,7 +66,7 @@ def report_conversion_ajax_failure(xhr):
nonlocal current_state
current_state = 'configuring'
apply_state_to_markup()
error_dialog(_('Failed to start conversion'), _(
error_dialog(_('Failed to convert'), _(
'Could not convert {}. Click "Show details" for more'
' information').format(conversion_data.title),
xhr.error_html
@ -104,14 +104,15 @@ def on_conversion_status(end_type, xhr, ev):
if response.running:
c = container_for_current_state()
c.querySelector('progress').value = response.percent
c.querySelector('.progress-msg').textContent = response.msg
if response.msg:
c.querySelector('.progress-msg').textContent = response.msg
check_for_conversion_status()
else:
if response.ok:
current_state = 'converted'
apply_state_to_markup()
conversion_data.fmt = response.fmt
conversion_data.size = response.size
current_state = 'converted'
apply_state_to_markup()
else:
show_failure(response)
else: