mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Implement reloading of book
This commit is contained in:
parent
b2be6727f6
commit
377b90ea0d
@ -122,7 +122,7 @@ def save_metadata(metadata, f):
|
|||||||
f.seek(0), f.truncate(), f.write(as_bytes(json.dumps(metadata, indent=2)))
|
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)
|
st = os.stat(path)
|
||||||
key = book_hash(path, st.st_size, st.st_mtime)
|
key = book_hash(path, st.st_size, st.st_mtime)
|
||||||
finished_path = safe_makedirs(os.path.join(book_cache_dir(), 'f'))
|
finished_path = safe_makedirs(os.path.join(book_cache_dir(), 'f'))
|
||||||
@ -135,8 +135,12 @@ def prepare_book(path, convert_func=do_convert, max_age=30 * DAY):
|
|||||||
metadata = {'entries': {}, 'last_clear_at': 0}
|
metadata = {'entries': {}, 'last_clear_at': 0}
|
||||||
entries = metadata['entries']
|
entries = metadata['entries']
|
||||||
instances = entries.setdefault(key, [])
|
instances = entries.setdefault(key, [])
|
||||||
for instance in instances:
|
for instance in tuple(instances):
|
||||||
if instance['status'] == 'finished':
|
if instance['status'] == 'finished':
|
||||||
|
if force:
|
||||||
|
robust_rmtree(os.path.join(finished_path, instance['path']))
|
||||||
|
instances.remove(instance)
|
||||||
|
else:
|
||||||
instance['atime'] = time.time()
|
instance['atime'] = time.time()
|
||||||
save_metadata(metadata, f)
|
save_metadata(metadata, f)
|
||||||
return os.path.join(finished_path, instance['path'])
|
return os.path.join(finished_path, instance['path'])
|
||||||
@ -234,6 +238,12 @@ def find_tests():
|
|||||||
third_path = prepare_book(book_src, convert_func=convert_mock)
|
third_path = prepare_book(book_src, convert_func=convert_mock)
|
||||||
self.assertNotEqual(path, third_path)
|
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
|
# Test cache expiry
|
||||||
open(book_src, 'wb').write(b'bcd')
|
open(book_src, 'wb').write(b'bcd')
|
||||||
prepare_book(book_src, convert_func=convert_mock, max_age=-1000)
|
prepare_book(book_src, convert_func=convert_mock, max_age=-1000)
|
||||||
|
@ -59,6 +59,7 @@ class EbookViewer(MainWindow):
|
|||||||
self.inspector_dock = create_dock(_('Inspector'), 'inspector', Qt.RightDockWidgetArea)
|
self.inspector_dock = create_dock(_('Inspector'), 'inspector', Qt.RightDockWidgetArea)
|
||||||
self.web_view = WebView(self)
|
self.web_view = WebView(self)
|
||||||
self.web_view.cfi_changed.connect(self.cfi_changed)
|
self.web_view.cfi_changed.connect(self.cfi_changed)
|
||||||
|
self.web_view.reload_book.connect(self.reload_book)
|
||||||
self.setCentralWidget(self.web_view)
|
self.setCentralWidget(self.web_view)
|
||||||
|
|
||||||
def handle_commandline_arg(self, arg):
|
def handle_commandline_arg(self, arg):
|
||||||
@ -76,18 +77,22 @@ class EbookViewer(MainWindow):
|
|||||||
self.load_ebook(path, open_at=open_at)
|
self.load_ebook(path, open_at=open_at)
|
||||||
self.raise_()
|
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
|
# TODO: Implement open_at
|
||||||
self.web_view.show_preparing_message()
|
self.web_view.show_preparing_message()
|
||||||
self.save_annotations()
|
self.save_annotations()
|
||||||
self.current_book_data = {}
|
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.daemon = True
|
||||||
t.start()
|
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:
|
try:
|
||||||
ans = prepare_book(pathtoebook)
|
ans = prepare_book(pathtoebook, force=reload_book)
|
||||||
except WorkerError as e:
|
except WorkerError as e:
|
||||||
self.book_prepared.emit(False, {'exception': e, 'tb': e.orig_tb, 'pathtoebook': pathtoebook})
|
self.book_prepared.emit(False, {'exception': e, 'tb': e.orig_tb, 'pathtoebook': pathtoebook})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -167,6 +167,7 @@ def create_profile():
|
|||||||
class ViewerBridge(Bridge):
|
class ViewerBridge(Bridge):
|
||||||
|
|
||||||
set_session_data = from_js(object, object)
|
set_session_data = from_js(object, object)
|
||||||
|
reload_book = from_js()
|
||||||
|
|
||||||
create_view = to_js()
|
create_view = to_js()
|
||||||
show_preparing_message = to_js()
|
show_preparing_message = to_js()
|
||||||
@ -244,6 +245,7 @@ class Inspector(QWidget):
|
|||||||
class WebView(RestartingWebEngineView):
|
class WebView(RestartingWebEngineView):
|
||||||
|
|
||||||
cfi_changed = pyqtSignal(object)
|
cfi_changed = pyqtSignal(object)
|
||||||
|
reload_book = pyqtSignal()
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
self._host_widget = None
|
self._host_widget = None
|
||||||
@ -256,6 +258,7 @@ class WebView(RestartingWebEngineView):
|
|||||||
self._page = WebPage(self)
|
self._page = WebPage(self)
|
||||||
self.bridge.bridge_ready.connect(self.on_bridge_ready)
|
self.bridge.bridge_ready.connect(self.on_bridge_ready)
|
||||||
self.bridge.set_session_data.connect(self.set_session_data)
|
self.bridge.set_session_data.connect(self.set_session_data)
|
||||||
|
self.bridge.reload_book.connect(self.reload_book)
|
||||||
self.pending_bridge_ready_actions = {}
|
self.pending_bridge_ready_actions = {}
|
||||||
self.setPage(self._page)
|
self.setPage(self._page)
|
||||||
self.setAcceptDrops(False)
|
self.setAcceptDrops(False)
|
||||||
|
@ -72,4 +72,6 @@ ui_operations = {
|
|||||||
'update_url_state': None,
|
'update_url_state': None,
|
||||||
'update_last_read_time': None,
|
'update_last_read_time': None,
|
||||||
'show_error': None,
|
'show_error': None,
|
||||||
|
'redisplay_book': None,
|
||||||
|
'reload_book': None,
|
||||||
}
|
}
|
||||||
|
@ -5,19 +5,21 @@ from __python__ import bound_methods, hash_literals
|
|||||||
from elementmaker import E
|
from elementmaker import E
|
||||||
from gettext import gettext as _
|
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.library_data import sync_library_books
|
||||||
from book_list.router import home
|
from book_list.router import home
|
||||||
from book_list.theme import get_color
|
from book_list.theme import get_color
|
||||||
from dom import add_extra_css, build_rule, clear, set_css, svgicon, unique_id
|
from dom import add_extra_css, build_rule, clear, set_css, svgicon, unique_id
|
||||||
from modals import error_dialog
|
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.goto import create_goto_panel
|
||||||
from read_book.prefs.font_size import create_font_size_panel
|
from read_book.prefs.font_size import create_font_size_panel
|
||||||
from read_book.prefs.main import create_prefs_panel
|
from read_book.prefs.main import create_prefs_panel
|
||||||
from read_book.toc import create_toc_panel
|
from read_book.toc import create_toc_panel
|
||||||
from read_book.word_actions import create_word_actions_panel
|
from read_book.word_actions import create_word_actions_panel
|
||||||
from session import get_device_uuid
|
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
|
from widgets import create_button, create_spinner
|
||||||
|
|
||||||
|
|
||||||
@ -86,6 +88,10 @@ class DeleteBook: # {{{
|
|||||||
pass # Dont allow panel to be closed by a click
|
pass # Dont allow panel to be closed by a click
|
||||||
|
|
||||||
def delete_book(self):
|
def delete_book(self):
|
||||||
|
if runtime.is_standalone_viewer:
|
||||||
|
if self.reload_book:
|
||||||
|
ui_operations.reload_book()
|
||||||
|
return
|
||||||
self.show_working()
|
self.show_working()
|
||||||
view = self.overlay.view
|
view = self.overlay.view
|
||||||
view.ui.db.delete_book(view.book, def(book, errmsg):
|
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)
|
view.ui.show_error(_('Failed to delete book'), _('Failed to delete book from local storage, click "Show details" for more information.'), errmsg)
|
||||||
else:
|
else:
|
||||||
if self.reload_book:
|
if self.reload_book:
|
||||||
get_read_ui().reload_book()
|
ui_operations.reload_book()
|
||||||
else:
|
else:
|
||||||
home()
|
home()
|
||||||
)
|
)
|
||||||
@ -207,6 +213,14 @@ class MainOverlay:
|
|||||||
|
|
||||||
return E.li(icon, '\xa0', text, onclick=action, title=tooltip)
|
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
|
actions_div = E.div( # actions
|
||||||
E.ul(
|
E.ul(
|
||||||
ac(_('Home'), _('Return to list of books'), def(): home();, 'home'),
|
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'),
|
ac(_('Go to'), _('Go to a specific location in the book'), self.overlay.show_goto, 'chevron-right'),
|
||||||
),
|
),
|
||||||
|
|
||||||
E.ul(
|
reload_actions,
|
||||||
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')
|
|
||||||
),
|
|
||||||
|
|
||||||
E.ul(
|
E.ul(
|
||||||
ac(_('Table of Contents'), None, self.overlay.show_toc, 'TC', True),
|
ac(_('Table of Contents'), None, self.overlay.show_toc, 'TC', True),
|
||||||
@ -350,7 +360,7 @@ class PrefsOverlay: # {{{
|
|||||||
def on_hide(self):
|
def on_hide(self):
|
||||||
if self.changes_occurred:
|
if self.changes_occurred:
|
||||||
self.changes_occurred = False
|
self.changes_occurred = False
|
||||||
get_read_ui().redisplay_book()
|
ui_operations.redisplay_book()
|
||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
@ -60,6 +60,8 @@ class ReadUI:
|
|||||||
ui_operations.update_url_state = self.update_url_state.bind(self)
|
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.update_last_read_time = self.db.update_last_read_time
|
||||||
ui_operations.show_error = self.show_error.bind(self)
|
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):
|
def on_resize(self):
|
||||||
self.view.on_resize()
|
self.view.on_resize()
|
||||||
|
@ -206,12 +206,22 @@ def onerror(msg, script_url, line_number, column_number, error_object):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def redisplay_book():
|
||||||
|
view.redisplay_book()
|
||||||
|
|
||||||
|
|
||||||
|
def reload_book():
|
||||||
|
to_python.reload_book()
|
||||||
|
|
||||||
|
|
||||||
if window is window.top:
|
if window is window.top:
|
||||||
# main
|
# main
|
||||||
ui_operations.get_file = get_file
|
ui_operations.get_file = get_file
|
||||||
ui_operations.get_mathjax_files = get_mathjax_files
|
ui_operations.get_mathjax_files = get_mathjax_files
|
||||||
ui_operations.update_url_state = update_url_state
|
ui_operations.update_url_state = update_url_state
|
||||||
ui_operations.show_error = show_error
|
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'))
|
document.body.appendChild(E.div(id='view'))
|
||||||
window.onerror = onerror
|
window.onerror = onerror
|
||||||
create_modal_container()
|
create_modal_container()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user