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()
|
||||
|
||||
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)
|
||||
else:
|
||||
error_dialog(title, msg, det_msg)
|
||||
@ -347,6 +347,24 @@ class DB:
|
||||
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):
|
||||
c = self.idb.transaction('mathjax').objectStore('mathjax').openCursor()
|
||||
c.onerror = def(event):
|
||||
|
@ -3,14 +3,16 @@
|
||||
from __python__ import bound_methods, hash_literals
|
||||
|
||||
from elementmaker import E
|
||||
from gettext import gettext as _
|
||||
|
||||
from book_list.theme import get_color
|
||||
from complete import create_search_bar
|
||||
from dom import add_extra_css, build_rule, svgicon
|
||||
from gettext import gettext as _
|
||||
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.shortcuts import shortcut_for_key_event
|
||||
from worker import start_worker
|
||||
|
||||
CLASS_NAME = 'book-search-container'
|
||||
|
||||
@ -42,6 +44,22 @@ class SearchOverlay:
|
||||
'\xa0', next_button, '\xa0', prev_button, '\xa0', close_button
|
||||
))
|
||||
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):
|
||||
if event.key is 'Escape' or event.key is 'Esc':
|
||||
@ -117,3 +135,6 @@ def find_in_spine(names, book, text, proceed):
|
||||
proceed(None)
|
||||
|
||||
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):
|
||||
m = ρσ_get_module(window.iframe_entry_point)
|
||||
m = ρσ_get_module(entry_point)
|
||||
main = m?.main
|
||||
if main:
|
||||
main()
|
||||
@ -69,3 +69,4 @@ if document?:
|
||||
toplevel_main()
|
||||
elif self?:
|
||||
entry_point = self.location.hash[1:]
|
||||
worker_main(entry_point)
|
||||
|
Loading…
x
Reference in New Issue
Block a user