Implement reloading of book

This commit is contained in:
Kovid Goyal 2019-08-06 09:40:35 +05:30
parent b2be6727f6
commit 377b90ea0d
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
7 changed files with 60 additions and 18 deletions

View File

@ -122,7 +122,7 @@ def save_metadata(metadata, f):
f.seek(0), f.truncate(), f.write(as_bytes(json.dumps(metadata, indent=2)))
def prepare_book(path, convert_func=do_convert, max_age=30 * DAY):
def prepare_book(path, convert_func=do_convert, max_age=30 * DAY, force=False):
st = os.stat(path)
key = book_hash(path, st.st_size, st.st_mtime)
finished_path = safe_makedirs(os.path.join(book_cache_dir(), 'f'))
@ -135,11 +135,15 @@ def prepare_book(path, convert_func=do_convert, max_age=30 * DAY):
metadata = {'entries': {}, 'last_clear_at': 0}
entries = metadata['entries']
instances = entries.setdefault(key, [])
for instance in instances:
for instance in tuple(instances):
if instance['status'] == 'finished':
instance['atime'] = time.time()
save_metadata(metadata, f)
return os.path.join(finished_path, instance['path'])
if force:
robust_rmtree(os.path.join(finished_path, instance['path']))
instances.remove(instance)
else:
instance['atime'] = time.time()
save_metadata(metadata, f)
return os.path.join(finished_path, instance['path'])
instance = prepare_convert(temp_path, key, st)
instances.append(instance)
save_metadata(metadata, f)
@ -234,6 +238,12 @@ def find_tests():
third_path = prepare_book(book_src, convert_func=convert_mock)
self.assertNotEqual(path, third_path)
# Test force reload
fourth_path = prepare_book(book_src, convert_func=convert_mock)
self.ae(third_path, fourth_path)
fourth_path = prepare_book(book_src, convert_func=convert_mock, force=True)
self.assertNotEqual(third_path, fourth_path)
# Test cache expiry
open(book_src, 'wb').write(b'bcd')
prepare_book(book_src, convert_func=convert_mock, max_age=-1000)

View File

@ -59,6 +59,7 @@ class EbookViewer(MainWindow):
self.inspector_dock = create_dock(_('Inspector'), 'inspector', Qt.RightDockWidgetArea)
self.web_view = WebView(self)
self.web_view.cfi_changed.connect(self.cfi_changed)
self.web_view.reload_book.connect(self.reload_book)
self.setCentralWidget(self.web_view)
def handle_commandline_arg(self, arg):
@ -76,18 +77,22 @@ class EbookViewer(MainWindow):
self.load_ebook(path, open_at=open_at)
self.raise_()
def load_ebook(self, pathtoebook, open_at=None):
def load_ebook(self, pathtoebook, open_at=None, reload_book=False):
# TODO: Implement open_at
self.web_view.show_preparing_message()
self.save_annotations()
self.current_book_data = {}
t = Thread(name='LoadBook', target=self._load_ebook_worker, args=(pathtoebook, open_at))
t = Thread(name='LoadBook', target=self._load_ebook_worker, args=(pathtoebook, open_at, reload_book))
t.daemon = True
t.start()
def _load_ebook_worker(self, pathtoebook, open_at):
def reload_book(self):
if self.current_book_data:
self.load_ebook(self.current_book_data['pathtoebook'], reload_book=True)
def _load_ebook_worker(self, pathtoebook, open_at, reload_book):
try:
ans = prepare_book(pathtoebook)
ans = prepare_book(pathtoebook, force=reload_book)
except WorkerError as e:
self.book_prepared.emit(False, {'exception': e, 'tb': e.orig_tb, 'pathtoebook': pathtoebook})
except Exception as e:

View File

@ -167,6 +167,7 @@ def create_profile():
class ViewerBridge(Bridge):
set_session_data = from_js(object, object)
reload_book = from_js()
create_view = to_js()
show_preparing_message = to_js()
@ -244,6 +245,7 @@ class Inspector(QWidget):
class WebView(RestartingWebEngineView):
cfi_changed = pyqtSignal(object)
reload_book = pyqtSignal()
def __init__(self, parent=None):
self._host_widget = None
@ -256,6 +258,7 @@ class WebView(RestartingWebEngineView):
self._page = WebPage(self)
self.bridge.bridge_ready.connect(self.on_bridge_ready)
self.bridge.set_session_data.connect(self.set_session_data)
self.bridge.reload_book.connect(self.reload_book)
self.pending_bridge_ready_actions = {}
self.setPage(self._page)
self.setAcceptDrops(False)

View File

@ -72,4 +72,6 @@ ui_operations = {
'update_url_state': None,
'update_last_read_time': None,
'show_error': None,
'redisplay_book': None,
'reload_book': None,
}

View File

@ -5,19 +5,21 @@ from __python__ import bound_methods, hash_literals
from elementmaker import E
from gettext import gettext as _
from book_list.globals import get_read_ui
from book_list.library_data import sync_library_books
from book_list.router import home
from book_list.theme import get_color
from dom import add_extra_css, build_rule, clear, set_css, svgicon, unique_id
from modals import error_dialog
from utils import full_screen_element, request_full_screen, safe_set_inner_html, is_ios
from read_book.globals import ui_operations, runtime
from read_book.goto import create_goto_panel
from read_book.prefs.font_size import create_font_size_panel
from read_book.prefs.main import create_prefs_panel
from read_book.toc import create_toc_panel
from read_book.word_actions import create_word_actions_panel
from session import get_device_uuid
from utils import (
full_screen_element, is_ios, request_full_screen, safe_set_inner_html
)
from widgets import create_button, create_spinner
@ -86,6 +88,10 @@ class DeleteBook: # {{{
pass # Dont allow panel to be closed by a click
def delete_book(self):
if runtime.is_standalone_viewer:
if self.reload_book:
ui_operations.reload_book()
return
self.show_working()
view = self.overlay.view
view.ui.db.delete_book(view.book, def(book, errmsg):
@ -94,7 +100,7 @@ class DeleteBook: # {{{
view.ui.show_error(_('Failed to delete book'), _('Failed to delete book from local storage, click "Show details" for more information.'), errmsg)
else:
if self.reload_book:
get_read_ui().reload_book()
ui_operations.reload_book()
else:
home()
)
@ -207,6 +213,14 @@ class MainOverlay:
return E.li(icon, '\xa0', text, onclick=action, title=tooltip)
sync_action = ac(_('Sync'), _('Get last read position and annotations from the server'), self.overlay.sync_book, 'cloud-download')
delete_action = ac(_('Delete'), _('Delete this book from the device'), self.overlay.delete_book, 'trash')
reload_action = ac(_('Reload'), _('Reload this book from the {}').format( _('computer') if runtime.is_standalone_viewer else _('server')), self.overlay.reload_book, 'refresh')
if runtime.is_standalone_viewer:
reload_actions = E.ul(reload_action)
else:
reload_actions = E.ul(sync_action, delete_action, reload_action)
actions_div = E.div( # actions
E.ul(
ac(_('Home'), _('Return to list of books'), def(): home();, 'home'),
@ -219,11 +233,7 @@ class MainOverlay:
ac(_('Go to'), _('Go to a specific location in the book'), self.overlay.show_goto, 'chevron-right'),
),
E.ul(
ac(_('Sync'), _('Get last read position and annotations from the server'), self.overlay.sync_book, 'cloud-download'),
ac(_('Delete'), _('Delete this book from the device'), self.overlay.delete_book, 'trash'),
ac(_('Reload'), _('Reload this book from the server'), self.overlay.reload_book, 'refresh')
),
reload_actions,
E.ul(
ac(_('Table of Contents'), None, self.overlay.show_toc, 'TC', True),
@ -350,7 +360,7 @@ class PrefsOverlay: # {{{
def on_hide(self):
if self.changes_occurred:
self.changes_occurred = False
get_read_ui().redisplay_book()
ui_operations.redisplay_book()
# }}}

View File

@ -60,6 +60,8 @@ class ReadUI:
ui_operations.update_url_state = self.update_url_state.bind(self)
ui_operations.update_last_read_time = self.db.update_last_read_time
ui_operations.show_error = self.show_error.bind(self)
ui_operations.redisplay_book = self.redisplay_book.bind(self)
ui_operations.reload_book = self.reload_book.bind(self)
def on_resize(self):
self.view.on_resize()

View File

@ -206,12 +206,22 @@ def onerror(msg, script_url, line_number, column_number, error_object):
return True
def redisplay_book():
view.redisplay_book()
def reload_book():
to_python.reload_book()
if window is window.top:
# main
ui_operations.get_file = get_file
ui_operations.get_mathjax_files = get_mathjax_files
ui_operations.update_url_state = update_url_state
ui_operations.show_error = show_error
ui_operations.redisplay_book = redisplay_book
ui_operations.reload_book = reload_book
document.body.appendChild(E.div(id='view'))
window.onerror = onerror
create_modal_container()