mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
More work on server book conversion
This commit is contained in:
parent
27c79db06a
commit
3695c35229
@ -45,6 +45,20 @@ def load_defaults(name):
|
|||||||
return r
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def load_all_defaults():
|
||||||
|
ans = {}
|
||||||
|
for x in os.listdir(config_dir):
|
||||||
|
if x.endswith('.py'):
|
||||||
|
path = os.path.join(config_dir, x)
|
||||||
|
with ExclusiveFile(path) as f:
|
||||||
|
raw = f.read()
|
||||||
|
r = GuiRecommendations()
|
||||||
|
if raw:
|
||||||
|
r.deserialize(raw)
|
||||||
|
ans[os.path.splitext(x)[0]] = r.copy()
|
||||||
|
return ans
|
||||||
|
|
||||||
|
|
||||||
def save_specifics(db, book_id, recs):
|
def save_specifics(db, book_id, recs):
|
||||||
raw = recs.serialize()
|
raw = recs.serialize()
|
||||||
db.set_conversion_options(book_id, 'PIPE', raw)
|
db.set_conversion_options(book_id, 'PIPE', raw)
|
||||||
@ -146,14 +160,11 @@ def get_preferred_input_format_for_book(db, book_id):
|
|||||||
|
|
||||||
|
|
||||||
def sort_formats_by_preference(formats, prefs):
|
def sort_formats_by_preference(formats, prefs):
|
||||||
uprefs = [x.upper() for x in prefs]
|
uprefs = {x.upper():i for i, x in enumerate(prefs)}
|
||||||
|
|
||||||
def key(x):
|
def key(x):
|
||||||
try:
|
return uprefs.get(x.upper(), len(prefs))
|
||||||
return uprefs.index(x.upper())
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
return len(prefs)
|
|
||||||
return sorted(formats, key=key)
|
return sorted(formats, key=key)
|
||||||
|
|
||||||
|
|
||||||
@ -188,5 +199,16 @@ def get_output_formats(preferred_output_format):
|
|||||||
fmts.append(pfo)
|
fmts.append(pfo)
|
||||||
else:
|
else:
|
||||||
fmts = list(sorted(all_formats,
|
fmts = list(sorted(all_formats,
|
||||||
key=lambda x:{'EPUB':'!A', 'MOBI':'!B'}.get(x.upper(), x)))
|
key=lambda x:{'EPUB':'!A', 'AZW3':'!B', 'MOBI':'!C'}.get(x.upper(), x)))
|
||||||
|
return fmts
|
||||||
|
|
||||||
|
|
||||||
|
def get_sorted_output_formats():
|
||||||
|
preferred_output_format = prefs['output_format'].upper()
|
||||||
|
fmts = get_output_formats(preferred_output_format)
|
||||||
|
try:
|
||||||
|
fmts.remove(preferred_output_format)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
fmts.insert(0, preferred_output_format)
|
||||||
return fmts
|
return fmts
|
||||||
|
44
src/calibre/srv/convert.py
Normal file
44
src/calibre/srv/convert.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#!/usr/bin/env python2
|
||||||
|
# vim:fileencoding=utf-8
|
||||||
|
# License: GPLv3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||||
|
|
||||||
|
from calibre.srv.errors import BookNotFound
|
||||||
|
from calibre.srv.routes import endpoint, json
|
||||||
|
from calibre.srv.utils import get_library_data
|
||||||
|
|
||||||
|
|
||||||
|
def conversion_defaults():
|
||||||
|
from calibre.ebooks.conversion.config import load_all_defaults
|
||||||
|
ans = getattr(conversion_defaults, 'ans', None)
|
||||||
|
if ans is None:
|
||||||
|
ans = conversion_defaults.ans = load_all_defaults()
|
||||||
|
return ans
|
||||||
|
|
||||||
|
|
||||||
|
@endpoint('/conversion/book-data/{book_id}', postprocess=json, types={'book_id': int})
|
||||||
|
def conversion_data(ctx, rd, book_id):
|
||||||
|
from calibre.ebooks.conversion.config import (
|
||||||
|
NoSupportedInputFormats, get_input_format_for_book,
|
||||||
|
get_sorted_output_formats, load_specifics)
|
||||||
|
db = get_library_data(ctx, rd)[0]
|
||||||
|
if not ctx.has_id(rd, db, book_id):
|
||||||
|
raise BookNotFound(book_id, db)
|
||||||
|
try:
|
||||||
|
input_format, input_formats = get_input_format_for_book(db, book_id)
|
||||||
|
except NoSupportedInputFormats:
|
||||||
|
input_formats = []
|
||||||
|
else:
|
||||||
|
if input_format in input_formats:
|
||||||
|
input_formats.remove(input_format)
|
||||||
|
input_formats.insert(0, input_format)
|
||||||
|
ans = {
|
||||||
|
'input_formats': [x.upper() for x in input_formats],
|
||||||
|
'output_formats': get_sorted_output_formats(),
|
||||||
|
'conversion_defaults': conversion_defaults(),
|
||||||
|
'conversion_specifics': load_specifics(db, book_id),
|
||||||
|
'title': db.field_for('title', book_id),
|
||||||
|
'authors': db.field_for('authors', book_id),
|
||||||
|
}
|
||||||
|
return ans
|
@ -179,7 +179,7 @@ class Context(object):
|
|||||||
return old[1]
|
return old[1]
|
||||||
|
|
||||||
|
|
||||||
SRV_MODULES = ('ajax', 'books', 'cdb', 'code', 'content', 'legacy', 'opds', 'users_api')
|
SRV_MODULES = ('ajax', 'books', 'cdb', 'code', 'content', 'legacy', 'opds', 'users_api', 'convert')
|
||||||
|
|
||||||
|
|
||||||
class Handler(object):
|
class Handler(object):
|
||||||
|
@ -14,7 +14,7 @@ from book_list.library_data import (
|
|||||||
book_metadata, cover_url, current_library_id, current_virtual_library,
|
book_metadata, cover_url, current_library_id, current_virtual_library,
|
||||||
download_url, library_data, load_status, set_book_metadata
|
download_url, library_data, load_status, set_book_metadata
|
||||||
)
|
)
|
||||||
from book_list.router import back, home, open_book
|
from book_list.router import back, home, open_book, report_a_load_failure
|
||||||
from book_list.theme import get_color, get_font_size
|
from book_list.theme import get_color, get_font_size
|
||||||
from book_list.top_bar import add_button, clear_buttons, create_top_bar, set_title
|
from book_list.top_bar import add_button, clear_buttons, create_top_bar, set_title
|
||||||
from book_list.ui import query_as_href, set_panel_handler, show_panel
|
from book_list.ui import query_as_href, set_panel_handler, show_panel
|
||||||
@ -546,17 +546,10 @@ def create_book_details(container):
|
|||||||
|
|
||||||
|
|
||||||
def report_load_failure(container):
|
def report_load_failure(container):
|
||||||
err = E.div()
|
report_a_load_failure(
|
||||||
safe_set_inner_html(err, load_status.error_html)
|
container, _('Failed to load books from calibre library, with error:'),
|
||||||
container.appendChild(E.div(
|
load_status.error_html)
|
||||||
style='margin: 1ex 1em',
|
|
||||||
E.div(_('Failed to load books from calibre library, with error:')),
|
|
||||||
err,
|
|
||||||
E.div(
|
|
||||||
style='margin-top: 1em; border-top: solid 1px currentColor; padding-top: 1ex;',
|
|
||||||
E.a(onclick=def(): home(replace=True);, href='javascript: void(0)', style='color: blue', _('Go back to the home page')))
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def check_for_books_loaded():
|
def check_for_books_loaded():
|
||||||
|
89
src/pyj/book_list/convert_book.pyj
Normal file
89
src/pyj/book_list/convert_book.pyj
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
# vim:fileencoding=utf-8
|
||||||
|
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
from __python__ import bound_methods, hash_literals
|
||||||
|
|
||||||
|
from elementmaker import E
|
||||||
|
from gettext import gettext as _
|
||||||
|
|
||||||
|
from ajax import ajax
|
||||||
|
from book_list.book_details import report_load_failure
|
||||||
|
from book_list.library_data import load_status, url_books_query
|
||||||
|
from book_list.router import back, report_a_load_failure
|
||||||
|
from book_list.top_bar import create_top_bar
|
||||||
|
from book_list.ui import set_panel_handler
|
||||||
|
from dom import add_extra_css, build_rule, clear
|
||||||
|
from utils import conditional_timeout, parse_url_params
|
||||||
|
|
||||||
|
CLASS_NAME = 'convert-book-panel'
|
||||||
|
|
||||||
|
add_extra_css(def():
|
||||||
|
sel = '.' + CLASS_NAME + ' '
|
||||||
|
style = build_rule(sel, placeholder='TODO: add this')
|
||||||
|
return style
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
conversion_data = None
|
||||||
|
conversion_data_load_status = {'loading':True, 'ok':False, 'error_html':None, 'current_fetch': None}
|
||||||
|
|
||||||
|
|
||||||
|
def on_data_loaded(end_type, xhr, ev):
|
||||||
|
nonlocal conversion_data
|
||||||
|
conversion_data_load_status.current_fetch = None
|
||||||
|
|
||||||
|
def bad_load(msg):
|
||||||
|
conversion_data_load_status.ok = False
|
||||||
|
conversion_data_load_status.loading = False
|
||||||
|
conversion_data_load_status.error_html = msg or xhr.error_html
|
||||||
|
|
||||||
|
if end_type is 'load':
|
||||||
|
conversion_data = JSON.parse(xhr.responseText)
|
||||||
|
elif end_type is 'abort':
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
bad_load()
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_conversion_data(book_id):
|
||||||
|
if conversion_data_load_status.current_fetch:
|
||||||
|
conversion_data_load_status.current_fetch.abort()
|
||||||
|
query = url_books_query()
|
||||||
|
conversion_data_load_status.loading = True
|
||||||
|
conversion_data_load_status.ok = False
|
||||||
|
conversion_data_load_status.error_html = None
|
||||||
|
conversion_data_load_status.current_fetch = ajax(f'conversion/books-data/{book_id}', on_data_loaded, query=query)
|
||||||
|
conversion_data_load_status.current_fetch.send()
|
||||||
|
|
||||||
|
|
||||||
|
def on_close(container_id):
|
||||||
|
back()
|
||||||
|
|
||||||
|
|
||||||
|
def check_for_data_loaded():
|
||||||
|
container = this
|
||||||
|
if load_status.loading or conversion_data_load_status.loading:
|
||||||
|
conditional_timeout(container.id, 5, check_for_data_loaded)
|
||||||
|
return
|
||||||
|
container = container.lastChild
|
||||||
|
clear(container)
|
||||||
|
if not load_status.ok:
|
||||||
|
report_load_failure(container)
|
||||||
|
return
|
||||||
|
if not conversion_data_load_status.ok:
|
||||||
|
report_a_load_failure(
|
||||||
|
container, _('Failed to load conversion data from calibre, with error:'),
|
||||||
|
conversion_data_load_status.error_html)
|
||||||
|
# create_convert_book(container)
|
||||||
|
|
||||||
|
|
||||||
|
def init(container_id):
|
||||||
|
container = document.getElementById(container_id)
|
||||||
|
create_top_bar(container, title=_('Convert book'), action=on_close.bind(None, container_id), icon='close')
|
||||||
|
container.appendChild(E.div(class_=CLASS_NAME))
|
||||||
|
container.lastChild.appendChild(E.div(_('Loading conversion data, please wait...'), style='margin: 1ex 1em'))
|
||||||
|
conditional_timeout(container_id, 5, check_for_data_loaded)
|
||||||
|
q = parse_url_params()
|
||||||
|
fetch_conversion_data(q.book_id)
|
||||||
|
|
||||||
|
|
||||||
|
set_panel_handler('convert_book', init)
|
@ -2,11 +2,17 @@
|
|||||||
# License: GPL v3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
|
# License: GPL v3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
from __python__ import bound_methods, hash_literals
|
from __python__ import bound_methods, hash_literals
|
||||||
|
|
||||||
|
from elementmaker import E
|
||||||
|
from gettext import gettext as _
|
||||||
|
|
||||||
from book_list.constants import book_list_container_id, read_book_container_id
|
from book_list.constants import book_list_container_id, read_book_container_id
|
||||||
from book_list.globals import get_current_query
|
from book_list.globals import get_current_query
|
||||||
from book_list.library_data import current_library_id
|
from book_list.library_data import current_library_id
|
||||||
from modals import close_all_modals
|
from modals import close_all_modals
|
||||||
from utils import encode_query_with_path, parse_url_params, request_full_screen
|
from utils import (
|
||||||
|
encode_query_with_path, parse_url_params, request_full_screen,
|
||||||
|
safe_set_inner_html
|
||||||
|
)
|
||||||
|
|
||||||
mode_handlers = {}
|
mode_handlers = {}
|
||||||
default_mode_handler = None
|
default_mode_handler = None
|
||||||
@ -89,5 +95,20 @@ def back():
|
|||||||
q = {}
|
q = {}
|
||||||
push_state(q, replace=True)
|
push_state(q, replace=True)
|
||||||
|
|
||||||
|
|
||||||
def home(replace=False):
|
def home(replace=False):
|
||||||
push_state({})
|
push_state({})
|
||||||
|
|
||||||
|
|
||||||
|
def report_a_load_failure(container, msg, error_html):
|
||||||
|
err = E.div()
|
||||||
|
safe_set_inner_html(err, error_html)
|
||||||
|
container.appendChild(E.div(
|
||||||
|
style='margin: 1ex 1em',
|
||||||
|
E.div(msg),
|
||||||
|
err,
|
||||||
|
E.div(
|
||||||
|
style='margin-top: 1em; border-top: solid 1px currentColor; padding-top: 1ex;',
|
||||||
|
E.a(onclick=def(): home(replace=True);, href='javascript: void(0)', style='color: blue', _('Go back to the home page')))
|
||||||
|
),
|
||||||
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user