mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Start work on threaded search for browser viewer
This commit is contained in:
parent
ebd5711134
commit
a6f1bea259
@ -86,7 +86,7 @@ class DB:
|
|||||||
self.initialize_stage1()
|
self.initialize_stage1()
|
||||||
|
|
||||||
def show_error(self, title, msg, det_msg):
|
def show_error(self, title, msg, det_msg):
|
||||||
if is_reading_book():
|
if not window? or is_reading_book():
|
||||||
self.show_read_book_error(title, msg, det_msg)
|
self.show_read_book_error(title, msg, det_msg)
|
||||||
else:
|
else:
|
||||||
error_dialog(title, msg, det_msg)
|
error_dialog(title, msg, det_msg)
|
||||||
@ -347,6 +347,24 @@ class DB:
|
|||||||
proceed(result, name, mt, book)
|
proceed(result, name, mt, book)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def get_book_file(self, book_hash, stored_files, name, proceed):
|
||||||
|
stores = ['files']
|
||||||
|
key = file_store_name({'book_hash': book_hash}, name)
|
||||||
|
transaction = self.idb.transaction(stores)
|
||||||
|
req = transaction.objectStore(stores[0]).get(key)
|
||||||
|
req.onsuccess = def(event):
|
||||||
|
if not req.result:
|
||||||
|
proceed({'ok': False, 'name': name, 'details': 'ENOENT'})
|
||||||
|
return
|
||||||
|
fdata = stored_files[key]
|
||||||
|
mt = fdata.mimetype or 'application/octet-stream'
|
||||||
|
if fdata.encoded:
|
||||||
|
result = Blob([base64decode(result)], {'type':mt})
|
||||||
|
proceed({'ok': True, 'result': result, 'name': name, 'mt': mt})
|
||||||
|
req.onerror = def(event):
|
||||||
|
details = get_error_details(event)
|
||||||
|
proceed({'ok': False, 'name': name, 'details': details})
|
||||||
|
|
||||||
def get_mathjax_files(self, proceed):
|
def get_mathjax_files(self, proceed):
|
||||||
c = self.idb.transaction('mathjax').objectStore('mathjax').openCursor()
|
c = self.idb.transaction('mathjax').objectStore('mathjax').openCursor()
|
||||||
c.onerror = def(event):
|
c.onerror = def(event):
|
||||||
|
@ -3,14 +3,16 @@
|
|||||||
from __python__ import bound_methods, hash_literals
|
from __python__ import bound_methods, hash_literals
|
||||||
|
|
||||||
from elementmaker import E
|
from elementmaker import E
|
||||||
from gettext import gettext as _
|
|
||||||
|
|
||||||
from book_list.theme import get_color
|
from book_list.theme import get_color
|
||||||
from complete import create_search_bar
|
from complete import create_search_bar
|
||||||
from dom import add_extra_css, build_rule, svgicon
|
from dom import add_extra_css, build_rule, svgicon
|
||||||
|
from gettext import gettext as _
|
||||||
from read_book.globals import ui_operations
|
from read_book.globals import ui_operations
|
||||||
|
from read_book.search_worker import worker_main
|
||||||
from read_book.resources import text_from_serialized_html
|
from read_book.resources import text_from_serialized_html
|
||||||
from read_book.shortcuts import shortcut_for_key_event
|
from read_book.shortcuts import shortcut_for_key_event
|
||||||
|
from worker import start_worker
|
||||||
|
|
||||||
CLASS_NAME = 'book-search-container'
|
CLASS_NAME = 'book-search-container'
|
||||||
|
|
||||||
@ -42,6 +44,22 @@ class SearchOverlay:
|
|||||||
'\xa0', next_button, '\xa0', prev_button, '\xa0', close_button
|
'\xa0', next_button, '\xa0', prev_button, '\xa0', close_button
|
||||||
))
|
))
|
||||||
c.firstChild.addEventListener('keydown', self.onkeydown, {'passive': False})
|
c.firstChild.addEventListener('keydown', self.onkeydown, {'passive': False})
|
||||||
|
self._worker = None
|
||||||
|
self.request_counter = 0
|
||||||
|
|
||||||
|
@property
|
||||||
|
def worker(self):
|
||||||
|
if not self._worker:
|
||||||
|
self._worker = start_worker('read_book.search')
|
||||||
|
return self._worker
|
||||||
|
|
||||||
|
def queue_search(self, book, current_name):
|
||||||
|
spine = book.manifest.spine
|
||||||
|
self.request_counter += 1
|
||||||
|
self.worker.postMessage({
|
||||||
|
'type': 'search', 'book_hash': book.book_hash, 'spine': spine, 'current_name': current_name,
|
||||||
|
'id': self.request_counter, 'stored_files': book.stored_files
|
||||||
|
})
|
||||||
|
|
||||||
def onkeydown(self, event):
|
def onkeydown(self, event):
|
||||||
if event.key is 'Escape' or event.key is 'Esc':
|
if event.key is 'Escape' or event.key is 'Esc':
|
||||||
@ -117,3 +135,6 @@ def find_in_spine(names, book, text, proceed):
|
|||||||
proceed(None)
|
proceed(None)
|
||||||
|
|
||||||
do_one()
|
do_one()
|
||||||
|
|
||||||
|
|
||||||
|
main = worker_main
|
||||||
|
102
src/pyj/read_book/search_worker.pyj
Normal file
102
src/pyj/read_book/search_worker.pyj
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
# vim:fileencoding=utf-8
|
||||||
|
# License: GPL v3 Copyright: 2021, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
from __python__ import bound_methods, hash_literals
|
||||||
|
|
||||||
|
from read_book.db import DB
|
||||||
|
|
||||||
|
GET_SPINE_FAILED = 1
|
||||||
|
CONNECT_FAILED = 2
|
||||||
|
UNHANDLED_ERROR = 3
|
||||||
|
DB_ERROR = 4
|
||||||
|
|
||||||
|
|
||||||
|
class Worker:
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.db = None
|
||||||
|
self.connected_to_db = False
|
||||||
|
self.pending_search = None
|
||||||
|
self.searching = False
|
||||||
|
self.current_query = None
|
||||||
|
self.current_query_id = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def initialize_error_msg(self):
|
||||||
|
return self.db?.initialize_error_msg
|
||||||
|
|
||||||
|
|
||||||
|
wc = Worker()
|
||||||
|
|
||||||
|
|
||||||
|
def send_search_complete():
|
||||||
|
self.postMessage({'type': 'search_complete', 'id': wc.current_query_id})
|
||||||
|
wc.current_query = wc.current_query_id = None
|
||||||
|
|
||||||
|
|
||||||
|
def queue_next_spine_item(spine_idx):
|
||||||
|
name = wc.current_query.spine[spine_idx]
|
||||||
|
if not name:
|
||||||
|
send_search_complete()
|
||||||
|
return
|
||||||
|
query = wc.current_query
|
||||||
|
wc.db.get_book_file(query.book_hash, query.stored_files, name, got_spine_item.bind(None, query.id, spine_idx))
|
||||||
|
|
||||||
|
|
||||||
|
def got_spine_item(query_id, spine_idx, result):
|
||||||
|
if query_id is not wc.current_query_id:
|
||||||
|
return
|
||||||
|
if result.ok:
|
||||||
|
queue_next_spine_item(spine_idx + 1)
|
||||||
|
else:
|
||||||
|
if result.details is 'ENOENT':
|
||||||
|
queue_next_spine_item(spine_idx + 1)
|
||||||
|
else:
|
||||||
|
send_error(GET_SPINE_FAILED, result.details)
|
||||||
|
wc.current_query = wc.current_query_id = None
|
||||||
|
|
||||||
|
|
||||||
|
def perform_search(query):
|
||||||
|
wc.current_query = query
|
||||||
|
wc.current_query_id = query.id
|
||||||
|
if not query.spine?.length:
|
||||||
|
send_search_complete()
|
||||||
|
return
|
||||||
|
idx = query.spine.indexOf(query.current_name)
|
||||||
|
if idx < 0:
|
||||||
|
idx = 0
|
||||||
|
queue_next_spine_item(idx)
|
||||||
|
|
||||||
|
|
||||||
|
def worker_connection_done():
|
||||||
|
wc.connected_to_db = True
|
||||||
|
if not wc.initialize_error_msg:
|
||||||
|
if wc.pending_search:
|
||||||
|
s = wc.pending_search
|
||||||
|
wc.pending_search = None
|
||||||
|
perform_search(s)
|
||||||
|
|
||||||
|
|
||||||
|
def send_error(code, msg, error):
|
||||||
|
self.postMessage({'type': 'error', 'code': code, 'msg': msg, 'id': wc.current_query_id, 'error': error})
|
||||||
|
|
||||||
|
|
||||||
|
def on_worker_db_error(title, msg, details):
|
||||||
|
send_error(DB_ERROR, msg, {'title': title, 'msg': msg, 'details': details})
|
||||||
|
|
||||||
|
|
||||||
|
def worker_main():
|
||||||
|
wc.db = DB(worker_connection_done, on_worker_db_error)
|
||||||
|
|
||||||
|
self.onmessage = def(e):
|
||||||
|
if e.data.type is 'search':
|
||||||
|
wc.current_query_id = e.data.id
|
||||||
|
if wc.connected_to_db:
|
||||||
|
if wc.initialize_error_msg:
|
||||||
|
send_error(CONNECT_FAILED, wc.initialize_error_msg)
|
||||||
|
else:
|
||||||
|
perform_search(e.data)
|
||||||
|
else:
|
||||||
|
wc.pending_search = e.data
|
||||||
|
|
||||||
|
self.onerror = def(e):
|
||||||
|
send_error(UNHANDLED_ERROR, f'{e.line}:{e.message}')
|
@ -14,7 +14,7 @@ AUTO_UPDATE_THRESHOLD = 1000 # millisecs
|
|||||||
|
|
||||||
|
|
||||||
def worker_main(entry_point):
|
def worker_main(entry_point):
|
||||||
m = ρσ_get_module(window.iframe_entry_point)
|
m = ρσ_get_module(entry_point)
|
||||||
main = m?.main
|
main = m?.main
|
||||||
if main:
|
if main:
|
||||||
main()
|
main()
|
||||||
@ -69,3 +69,4 @@ if document?:
|
|||||||
toplevel_main()
|
toplevel_main()
|
||||||
elif self?:
|
elif self?:
|
||||||
entry_point = self.location.hash[1:]
|
entry_point = self.location.hash[1:]
|
||||||
|
worker_main(entry_point)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user