mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Viewer: Allow also using --open-at with book positions
This commit is contained in:
parent
221d8f73a4
commit
b9cb195804
@ -14,7 +14,7 @@ from PyQt5.QtWebEngineCore import QWebEngineUrlScheme
|
|||||||
from calibre import as_unicode, prints
|
from calibre import as_unicode, prints
|
||||||
from calibre.constants import FAKE_PROTOCOL, VIEWER_APP_UID, islinux
|
from calibre.constants import FAKE_PROTOCOL, VIEWER_APP_UID, islinux
|
||||||
from calibre.gui2 import Application, error_dialog, setup_gui_option_parser
|
from calibre.gui2 import Application, error_dialog, setup_gui_option_parser
|
||||||
from calibre.gui2.viewer.ui import EbookViewer
|
from calibre.gui2.viewer.ui import EbookViewer, is_float
|
||||||
from calibre.ptempfile import reset_base_dir
|
from calibre.ptempfile import reset_base_dir
|
||||||
from calibre.utils.config import JSONConfig
|
from calibre.utils.config import JSONConfig
|
||||||
from calibre.utils.ipc import RC, viewer_socket_address
|
from calibre.utils.ipc import RC, viewer_socket_address
|
||||||
@ -163,7 +163,7 @@ View an e-book.
|
|||||||
help=_('Force reload of all opened books'))
|
help=_('Force reload of all opened books'))
|
||||||
a('--open-at', default=None, help=_(
|
a('--open-at', default=None, help=_(
|
||||||
'The position at which to open the specified book. The position is '
|
'The position at which to open the specified book. The position is '
|
||||||
'a location you can get by using the Goto action in the viewer controls. '
|
'a location or position you can get by using the Go to->Location action in the viewer controls. '
|
||||||
'Alternately, you can use the form toc:something and it will open '
|
'Alternately, you can use the form toc:something and it will open '
|
||||||
'at the location of the first Table of Contents entry that contains '
|
'at the location of the first Table of Contents entry that contains '
|
||||||
'the string "something".'))
|
'the string "something".'))
|
||||||
@ -188,7 +188,7 @@ def main(args=sys.argv):
|
|||||||
parser = option_parser()
|
parser = option_parser()
|
||||||
opts, args = parser.parse_args(args)
|
opts, args = parser.parse_args(args)
|
||||||
|
|
||||||
if opts.open_at and not (opts.open_at.startswith('toc:') or opts.open_at.startswith('epubcfi(/')):
|
if opts.open_at and not (opts.open_at.startswith('toc:') or opts.open_at.startswith('epubcfi(/') or is_float(opts.open_at)):
|
||||||
raise SystemExit('Not a valid --open-at value: {}'.format(opts.open_at))
|
raise SystemExit('Not a valid --open-at value: {}'.format(opts.open_at))
|
||||||
|
|
||||||
listener = None
|
listener = None
|
||||||
|
@ -46,6 +46,15 @@ from polyglot.builtins import as_bytes, itervalues
|
|||||||
annotations_dir = os.path.join(viewer_config_dir, 'annots')
|
annotations_dir = os.path.join(viewer_config_dir, 'annots')
|
||||||
|
|
||||||
|
|
||||||
|
def is_float(x):
|
||||||
|
try:
|
||||||
|
float(x)
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def dock_defs():
|
def dock_defs():
|
||||||
Dock = namedtuple('Dock', 'name title initial_area allowed_areas')
|
Dock = namedtuple('Dock', 'name title initial_area allowed_areas')
|
||||||
ans = {}
|
ans = {}
|
||||||
@ -353,13 +362,15 @@ class EbookViewer(MainWindow):
|
|||||||
self.load_book_data()
|
self.load_book_data()
|
||||||
self.update_window_title()
|
self.update_window_title()
|
||||||
initial_cfi = self.initial_cfi_for_current_book()
|
initial_cfi = self.initial_cfi_for_current_book()
|
||||||
initial_toc_node = None
|
initial_toc_node = initial_bookpos = None
|
||||||
if open_at:
|
if open_at:
|
||||||
if open_at.startswith('toc:'):
|
if open_at.startswith('toc:'):
|
||||||
initial_toc_node = self.toc_model.node_id_for_text(open_at[len('toc:'):])
|
initial_toc_node = self.toc_model.node_id_for_text(open_at[len('toc:'):])
|
||||||
elif open_at.startswith('epubcfi(/'):
|
elif open_at.startswith('epubcfi(/'):
|
||||||
initial_cfi = open_at
|
initial_cfi = open_at
|
||||||
self.web_view.start_book_load(initial_cfi=initial_cfi, initial_toc_node=initial_toc_node)
|
elif is_float(open_at):
|
||||||
|
initial_bookpos = float(open_at)
|
||||||
|
self.web_view.start_book_load(initial_cfi=initial_cfi, initial_toc_node=initial_toc_node, initial_bookpos=initial_bookpos)
|
||||||
|
|
||||||
def load_book_data(self):
|
def load_book_data(self):
|
||||||
self.load_book_annotations()
|
self.load_book_annotations()
|
||||||
|
@ -502,9 +502,9 @@ class WebView(RestartingWebEngineView):
|
|||||||
for func, args in iteritems(self.pending_bridge_ready_actions):
|
for func, args in iteritems(self.pending_bridge_ready_actions):
|
||||||
getattr(self.bridge, func)(*args)
|
getattr(self.bridge, func)(*args)
|
||||||
|
|
||||||
def start_book_load(self, initial_cfi=None, initial_toc_node=None):
|
def start_book_load(self, initial_cfi=None, initial_toc_node=None, initial_bookpos=None):
|
||||||
key = (set_book_path.path,)
|
key = (set_book_path.path,)
|
||||||
self.execute_when_ready('start_book_load', key, initial_cfi, initial_toc_node, set_book_path.pathtoebook)
|
self.execute_when_ready('start_book_load', key, initial_cfi, initial_toc_node, initial_bookpos, set_book_path.pathtoebook)
|
||||||
|
|
||||||
def execute_when_ready(self, action, *args):
|
def execute_when_ready(self, action, *args):
|
||||||
if self.bridge.ready:
|
if self.bridge.ready:
|
||||||
|
@ -118,8 +118,7 @@ def create_location_overlay(current_position_data, overlay, container):
|
|||||||
|
|
||||||
def goto_pos():
|
def goto_pos():
|
||||||
src = document.querySelector(f'#{container_id} [name=newpos]')
|
src = document.querySelector(f'#{container_id} [name=newpos]')
|
||||||
val = max(0, min(1000 * float(src.value) / current_position_data.book_length, 1))
|
ui_operations.goto_book_position(float(src.value))
|
||||||
ui_operations.goto_frac(val)
|
|
||||||
overlay.hide()
|
overlay.hide()
|
||||||
|
|
||||||
container.lastChild.appendChild(E.div(
|
container.lastChild.appendChild(E.div(
|
||||||
|
@ -67,6 +67,7 @@ class ReadUI:
|
|||||||
ui_operations.update_font_size = self.update_font_size.bind(self)
|
ui_operations.update_font_size = self.update_font_size.bind(self)
|
||||||
ui_operations.goto_cfi = self.goto_cfi.bind(self)
|
ui_operations.goto_cfi = self.goto_cfi.bind(self)
|
||||||
ui_operations.goto_frac = self.goto_frac.bind(self)
|
ui_operations.goto_frac = self.goto_frac.bind(self)
|
||||||
|
ui_operations.goto_book_position = self.goto_book_position.bind(self)
|
||||||
ui_operations.delete_book = self.delete_book.bind(self)
|
ui_operations.delete_book = self.delete_book.bind(self)
|
||||||
ui_operations.focus_iframe = self.focus_iframe.bind(self)
|
ui_operations.focus_iframe = self.focus_iframe.bind(self)
|
||||||
ui_operations.toggle_toc = self.toggle_toc.bind(self)
|
ui_operations.toggle_toc = self.toggle_toc.bind(self)
|
||||||
@ -166,6 +167,9 @@ class ReadUI:
|
|||||||
def goto_frac(self, frac):
|
def goto_frac(self, frac):
|
||||||
return self.view.goto_frac(frac)
|
return self.view.goto_frac(frac)
|
||||||
|
|
||||||
|
def goto_book_position(self, bpos):
|
||||||
|
return self.view.goto_book_position(bpos)
|
||||||
|
|
||||||
def delete_book(self, book, proceed):
|
def delete_book(self, book, proceed):
|
||||||
self.db.delete_book(book, proceed)
|
self.db.delete_book(book, proceed)
|
||||||
|
|
||||||
|
@ -567,7 +567,7 @@ class View:
|
|||||||
cfi = '/' + rest
|
cfi = '/' + rest
|
||||||
return name, cfi
|
return name, cfi
|
||||||
|
|
||||||
def display_book(self, book, initial_cfi, initial_toc_node):
|
def display_book(self, book, initial_cfi, initial_toc_node, initial_bookpos):
|
||||||
self.hide_overlays()
|
self.hide_overlays()
|
||||||
self.iframe.focus()
|
self.iframe.focus()
|
||||||
is_current_book = self.book and self.book.key == book.key
|
is_current_book = self.book and self.book.key == book.key
|
||||||
@ -601,6 +601,9 @@ class View:
|
|||||||
navigated = False
|
navigated = False
|
||||||
if jstype(initial_toc_node) is 'number':
|
if jstype(initial_toc_node) is 'number':
|
||||||
navigated = self.goto_toc_node(initial_toc_node)
|
navigated = self.goto_toc_node(initial_toc_node)
|
||||||
|
if not navigated and jstype(initial_bookpos) is 'number':
|
||||||
|
navigated = True
|
||||||
|
self.goto_book_position(initial_bookpos)
|
||||||
if not navigated:
|
if not navigated:
|
||||||
self.show_name(name, initial_position=pos)
|
self.show_name(name, initial_position=pos)
|
||||||
sd = get_session_data()
|
sd = get_session_data()
|
||||||
@ -694,6 +697,10 @@ class View:
|
|||||||
else:
|
else:
|
||||||
self.show_name(chapter_name, initial_position={'type':'frac', 'frac':chapter_frac, 'replace_history':True})
|
self.show_name(chapter_name, initial_position={'type':'frac', 'frac':chapter_frac, 'replace_history':True})
|
||||||
|
|
||||||
|
def goto_book_position(self, bpos):
|
||||||
|
val = max(0, min(1000 * float(bpos) / self.current_position_data.book_length, 1))
|
||||||
|
return self.goto_frac(val)
|
||||||
|
|
||||||
def on_scroll_to_anchor(self, data):
|
def on_scroll_to_anchor(self, data):
|
||||||
self.show_name(data.name, initial_position={'type':'anchor', 'anchor':data.frag, 'replace_history':False})
|
self.show_name(data.name, initial_position={'type':'anchor', 'anchor':data.frag, 'replace_history':False})
|
||||||
|
|
||||||
|
@ -136,7 +136,7 @@ def show_error(title, msg, details):
|
|||||||
to_python.show_error(title, msg, details)
|
to_python.show_error(title, msg, details)
|
||||||
|
|
||||||
|
|
||||||
def manifest_received(key, initial_cfi, initial_toc_node, pathtoebook, end_type, xhr, ev):
|
def manifest_received(key, initial_cfi, initial_toc_node, initial_bookpos, pathtoebook, end_type, xhr, ev):
|
||||||
nonlocal book
|
nonlocal book
|
||||||
if end_type is 'load':
|
if end_type is 'load':
|
||||||
book = new_book(key, {})
|
book = new_book(key, {})
|
||||||
@ -148,7 +148,7 @@ def manifest_received(key, initial_cfi, initial_toc_node, pathtoebook, end_type,
|
|||||||
book.is_complete = True
|
book.is_complete = True
|
||||||
v'delete book.manifest["metadata"]'
|
v'delete book.manifest["metadata"]'
|
||||||
v'delete book.manifest["last_read_positions"]'
|
v'delete book.manifest["last_read_positions"]'
|
||||||
view.display_book(book, initial_cfi, initial_toc_node)
|
view.display_book(book, initial_cfi, initial_toc_node, initial_bookpos)
|
||||||
else:
|
else:
|
||||||
show_error(_('Could not open book'), _(
|
show_error(_('Could not open book'), _(
|
||||||
'Failed to load book manifest, click "Show details" for more info'),
|
'Failed to load book manifest, click "Show details" for more info'),
|
||||||
@ -230,8 +230,8 @@ def show_home_page():
|
|||||||
|
|
||||||
|
|
||||||
@from_python
|
@from_python
|
||||||
def start_book_load(key, initial_cfi, initial_toc_node, pathtoebook):
|
def start_book_load(key, initial_cfi, initial_toc_node, initial_bookpos, pathtoebook):
|
||||||
xhr = ajax('manifest', manifest_received.bind(None, key, initial_cfi, initial_toc_node, pathtoebook), ok_code=0)
|
xhr = ajax('manifest', manifest_received.bind(None, key, initial_cfi, initial_toc_node, initial_bookpos, pathtoebook), ok_code=0)
|
||||||
xhr.responseType = 'json'
|
xhr.responseType = 'json'
|
||||||
xhr.send()
|
xhr.send()
|
||||||
|
|
||||||
@ -308,6 +308,8 @@ if window is window.top:
|
|||||||
return view.goto_cfi(cfi)
|
return view.goto_cfi(cfi)
|
||||||
ui_operations.goto_frac = def(frac):
|
ui_operations.goto_frac = def(frac):
|
||||||
return view.goto_frac(frac)
|
return view.goto_frac(frac)
|
||||||
|
ui_operations.goto_book_position = def(bpos):
|
||||||
|
return view.goto_book_position(bpos)
|
||||||
ui_operations.toggle_toc = def():
|
ui_operations.toggle_toc = def():
|
||||||
to_python.toggle_toc()
|
to_python.toggle_toc()
|
||||||
ui_operations.toggle_bookmarks = def():
|
ui_operations.toggle_bookmarks = def():
|
||||||
|
Loading…
x
Reference in New Issue
Block a user