diff --git a/src/calibre/customize/ui.py b/src/calibre/customize/ui.py index 4d0e787040..26aa6169c5 100644 --- a/src/calibre/customize/ui.py +++ b/src/calibre/customize/ui.py @@ -446,14 +446,14 @@ def plugin_for_input_format(fmt): return plugin def all_input_formats(): - formats = set([]) + formats = set() for plugin in input_format_plugins(): for format in plugin.file_types: formats.add(format) return formats def available_input_formats(): - formats = set([]) + formats = set() for plugin in input_format_plugins(): if not is_disabled(plugin): for format in plugin.file_types: diff --git a/src/calibre/srv/code.py b/src/calibre/srv/code.py index 5320353cbe..32d34f486e 100644 --- a/src/calibre/srv/code.py +++ b/src/calibre/srv/code.py @@ -10,11 +10,13 @@ from threading import Lock from json import load as load_json_file from calibre import prepare_string_for_xml, as_unicode +from calibre.customize.ui import available_input_formats from calibre.db.view import sanitize_sort_field_name from calibre.srv.ajax import get_db, search_result from calibre.srv.errors import HTTPNotFound, HTTPBadRequest from calibre.srv.metadata import book_as_json, categories_as_json, icon_map from calibre.srv.routes import endpoint, json +from calibre.utils.config import prefs from calibre.utils.icu import sort_key from calibre.utils.search_query_parser import ParseException @@ -92,7 +94,7 @@ def interface_data(ctx, rd): Optional: ?num=50&sort=timestamp.desc&library_id= &search=''&extra_books='' ''' - ans = {'username':rd.username} + ans = {'username':rd.username, 'output_format':prefs['output_format'].upper(), 'input_formats':tuple(x.upper() for x in available_input_formats())} ans['library_map'], ans['default_library'] = ctx.library_map ud = {} if rd.username: diff --git a/src/calibre/srv/content.py b/src/calibre/srv/content.py index e6e895bcb4..1ba7a94f7a 100644 --- a/src/calibre/srv/content.py +++ b/src/calibre/srv/content.py @@ -269,4 +269,4 @@ def get(ctx, rd, what, book_id, library_id): try: return book_fmt(ctx, rd, library_id, db, book_id, what.lower()) except NoSuchFormat: - raise HTTPNotFound('No %r format for the book %r' % (what.lower(), book_id)) + raise HTTPNotFound('No %s format for the book %r' % (what.lower(), book_id)) diff --git a/src/pyj/book_list/book_details.pyj b/src/pyj/book_list/book_details.pyj index c947c6acf8..cdf38c3fd9 100644 --- a/src/pyj/book_list/book_details.pyj +++ b/src/pyj/book_list/book_details.pyj @@ -9,10 +9,32 @@ from elementmaker import E from gettext import gettext as _ from book_list.globals import get_boss from modals import error_dialog -from widgets import create_spinner +from widgets import create_spinner, create_button bd_counter = 0 +FORMAT_PRIORITIES = [ + 'EPUB', 'AZW3', 'DOCX', 'LIT', 'MOBI', 'ODT', 'RTF', 'MD', 'MARKDOWN', 'TXT', 'PDF' +] + +def sort_formats_key(fmt): + ans = FORMAT_PRIORITIES.indexOf(fmt) + if ans < 0: + ans = FORMAT_PRIORITIES.length + return ans + +def get_preferred_format(metadata, output_format, input_formats): + formats = (metadata and metadata.formats) or v'[]' + formats = [f.toUpperCase() for f in formats] + input_formats = {x.toUpperCase():True for x in input_formats} + fmt = output_format + if formats.length and formats.indexOf(fmt) == -1: + for q in sorted(formats, key=sort_formats_key): + if input_formats[q]: + fmt = q + break + return fmt.toUpperCase() + class BookDetailsPanel: def __init__(self, interface_data, book_list_container): @@ -26,6 +48,7 @@ class BookDetailsPanel: ) book_list_container.appendChild(div) self.interface_data = interface_data + self.current_book_id = None @property def container(self): @@ -40,6 +63,7 @@ class BookDetailsPanel: self.container.style.display = 'block' if val else 'none' def init(self, data): + self.current_book_id = None c = self.container clear(c) book_id = get_current_query()['book-id'] @@ -96,6 +120,7 @@ class BookDetailsPanel: c.lastChild.lastChild.innerHTML = xhr.error_html def render_book(self, book_id): + self.current_book_id = int(book_id) metadata = self.interface_data.metadata[book_id] get_boss().ui.set_title(metadata.title) cover_url = str.format('get/cover/{}/{}', book_id, self.interface_data['library_id']) @@ -108,10 +133,29 @@ class BookDetailsPanel: c = self.container c.appendChild(E.div( style='display:block; padding: 1ex 1em', - E.div(style='margin-right: 1em; float:left'), + E.div(style='margin-right: 1em; float:left', data_book_id='' + book_id), img )) + container = c.lastChild.firstChild + read_button = create_button(_('Read'), 'book', self.read_book.bind(self), _('Read this book')) + download_button = create_button(_('Download'), 'cloud-download', self.download_book.bind(self), str.format( + _('Download this book in the {} format'), self.preferred_format(book_id))) + row = E.div(read_button, '\xa0\xa0\xa0', download_button, style='margin-bottom: 1ex') + if not metadata.formats or not metadata.formats.length: + row.style.display = 'none' + container.appendChild(row) def on_img_err(self, err): img = err.target img.style.display = 'none' + + def preferred_format(self, book_id): + return get_preferred_format(self.interface_data.metadata[book_id], self.interface_data['output_format'], self.interface_data['input_formats']) + + def download_book(self): + book_id = self.current_book_id + fmt = self.preferred_format(book_id) + window.location = str.format('get/{}/{}/{}', fmt, book_id, self.interface_data.library_id) + + def read_book(self): + pass diff --git a/src/pyj/book_list/ui.pyj b/src/pyj/book_list/ui.pyj index 07116228e6..c83c0f1c4e 100644 --- a/src/pyj/book_list/ui.pyj +++ b/src/pyj/book_list/ui.pyj @@ -106,6 +106,8 @@ class UI: self.panel_map['book-details'] = bd = UIState(ClosePanelBar(_('Book Details')), main_panel=self.book_details_panel) bd.add_button(icon_name='random', tooltip=_('Pick another random book'), action=self.book_details_panel.show_random.bind(self.book_details_panel)) + bd.add_button(icon_name='book', tooltip=_('Read this book'), action=self.book_details_panel.read_book.bind(self.book_details_panel)) + bd.add_button(icon_name='cloud-download', tooltip=_('Download this book'), action=self.book_details_panel.download_book.bind(self.book_details_panel)) def create_prefences_panel(self, title, close_callback=None, panel_data=None): ans = UIState(ClosePanelBar(title), close_callback=close_callback, main_panel=self.prefs_panel, panel_data=panel_data)