View Single Post
Old 09-14-2024, 11:41 AM   #21
chaley
Grand Sorcerer
chaley ought to be getting tired of karma fortunes by now.chaley ought to be getting tired of karma fortunes by now.chaley ought to be getting tired of karma fortunes by now.chaley ought to be getting tired of karma fortunes by now.chaley ought to be getting tired of karma fortunes by now.chaley ought to be getting tired of karma fortunes by now.chaley ought to be getting tired of karma fortunes by now.chaley ought to be getting tired of karma fortunes by now.chaley ought to be getting tired of karma fortunes by now.chaley ought to be getting tired of karma fortunes by now.chaley ought to be getting tired of karma fortunes by now.
 
Posts: 12,476
Karma: 8025702
Join Date: Jan 2010
Location: Notts, England
Device: Kobo Libra 2
Try this template. On my machine and using your library the search completes in 4 or 5 seconds.

Note that it is suitable to be used as a stored template with 2 arguments. I tested it as "books_with_notes_containing_text" with this as the actual template search.
Click image for larger version

Name:	Clipboard01.jpg
Views:	157
Size:	71.4 KB
ID:	210811

Code:
python:
def evaluate(book, context):
    if context.arguments is None or len(context.arguments) != 2:
        # Set these to what you want
        field_name = 'authors'
        value_in_note = 'a'
    else:
        field_name = context.arguments[0]
        value_in_note = context.arguments[1]

    db = context.db.new_api

    # check if we have already cached the notes
    note_items = context.globals.get('items_with_notes', None)
    if note_items is not None:
        # We've already fetched which items have notes.
        # Get the cached search result values
        note_search_results = context.globals['note_search_results']
        item_name_map = context.globals['item_name_map']
    else:
        # First time. Get the items with notes and initialize
        # the search value cache.
        note_items = db.get_all_items_that_have_notes(field_name)
        context.globals['items_with_notes'] = note_items
        note_search_results = {}
        context.globals['note_search_results'] = note_search_results
        # db.get_item_id() uses a linear search. Avoid this by getting
        # and caching the map
        item_name_map = db.get_item_name_map(field_name)
        context.globals['item_name_map'] = item_name_map

    # Check if this book is a match -- that the field has a note containing
    # the desired text.
    
    # We must first get the item_id for the value in the field to be checked.
    field_value = book.get(field_name)
	if not field_value:
		return ''
    # if the field is multi-valued, use the first value
    if isinstance(field_value, list):
		if len(field_value) == 0:
			return ''
        field_value = field_value[0]
    # Now get the cached internal ID of the value in field_name
    item_id = item_name_map[field_value]

    # Does the item have a note? If not, give up now.
    if item_id not in note_items:
        return ''

    # The item has a note. Have we already checked it?
    if item_id not in note_search_results:
        # Item has a note but we haven't seen it before. Do the compare
        # on the plain text version of the note.
        result = ''
        # Get the note.
        note = db.notes_data_for(field_name, item_id)
        if note:
            # Get the plain text of the note.
            note = note['searchable_text'].partition('\n')[2]
        if note:
            # use a case insensitive compare to check if the search value is in the note
            from calibre.utils.icu import primary_contains
            result = 'Yes' if primary_contains(value_in_note, note) else ''
        # Cache the result of the comparison
        note_search_results[item_id] = result
        context.globals['note_search_results'] = note_search_results
    # Return the cached value
    return note_search_results.get(item_id, '')
chaley is offline   Reply With Quote