View Single Post
Old 12-18-2024, 04:02 AM   #58
Comfy.n
want to learn what I want
Comfy.n ought to be getting tired of karma fortunes by now.Comfy.n ought to be getting tired of karma fortunes by now.Comfy.n ought to be getting tired of karma fortunes by now.Comfy.n ought to be getting tired of karma fortunes by now.Comfy.n ought to be getting tired of karma fortunes by now.Comfy.n ought to be getting tired of karma fortunes by now.Comfy.n ought to be getting tired of karma fortunes by now.Comfy.n ought to be getting tired of karma fortunes by now.Comfy.n ought to be getting tired of karma fortunes by now.Comfy.n ought to be getting tired of karma fortunes by now.Comfy.n ought to be getting tired of karma fortunes by now.
 
Posts: 1,615
Karma: 7891011
Join Date: Sep 2020
Device: none
Quote:
Originally Posted by chaley View Post
I may have confused things, but lets put that aside.

I have an implementation that doesn't require the temporary VL but respects the current VL. It is a bit more complicated because I wanted to generalize it to any field, not just authors. To use what I describe below you must be running calibre 7.7 or later.

To use it, make a stored template named whatever you want -- I use "get_one_book_per_field_value". The template itself is:
Spoiler:
Code:
python:
def evaluate(book, context):
	field_name = context.arguments[0] if len(context.arguments) == 1 else None
	if field_name is None:
		raise NameError("The argument 'field' wasn't provided")

	db = context.db.new_api
	# Check if we have already computed the necessary data
	book_ids = context.globals.get('book_ids', None)
	if book_ids is None:
		candidates = context.globals.get('_candidates', db.all_book_ids())
		books = {}
		for book_id in db.search(query=''): # restrict the search to the current VL
			if book_id not in candidates:
				continue
			item_values = db.field_for(field_name, book_id)
			if item_values is None:
				continue
			if isinstance(item_values, str):
				item_values = (item_values,)
			for item_val in item_values:
				if item_val not in books or books[item_val]['count'] > len(item_values):
					books.pop(item_val, None)
					books[item_val] = {'count': len(item_values), 'book_id': book_id}
		context.globals['book_ids'] = frozenset(bn['book_id'] for bn in books.values())

	# Check if the current book is to be displayed
	book_ids = context.globals['book_ids']
	return '1' if book.id in book_ids else ''
This template takes one argument, the field (column) you are interested in (authors).

Next, make this template search:
Code:
template:"""program: get_one_book_per_field_value('authors')#@#:b:yes"""
It calls the above stored template with the argument "authors". I recommend you create a saved search with it. I did and named it "one_book_per_author". You now have @Katja_hbg's B.

You also need @Katja_hbg's A. To get it, put this in a stored template named what you want. I named it "item_has_notes". The template is
Spoiler:
Code:
python:
def evaluate(book, context):
	field_name = context.arguments[0] if len(context.arguments) == 1 else None
	if field_name is None:
		raise NameError("The argument for the field name wasn't provided")

	db = context.db.new_api
	items_with_notes = context.globals.get('items_with_notes')
	if items_with_notes is None:
		items_with_notes = db.get_all_items_that_have_notes(field_name)
		context.globals['items_with_notes'] = items_with_notes
		context.globals['item_name_map'] = db.get_item_name_map(field_name)
	item_name_map = context.globals['item_name_map']

	vals = book.get(field_name)
	if vals is None:
		return ''
	if isinstance(vals, str):
		vals = tuple((vals,))
	for val in vals:
		if item_name_map.get(val) in items_with_notes:
			return '1'
	return ''

This template also takes 1 argument, the field (column) name.

Now make another template search
Code:
template:"""program: item_has_notes('authors')#@#:b:yes"""
This calles the stored template with the field name "authors". Again, I recommend you save it as a search. I did that, naming it "author has notes".

You can now do searches like:
  • search:"=author has notes" and search:one_book_per_author
  • formats:epub and tags:foobar and search:one_book_per_author
  • search:one_book_per_author

All of this works for me. I hope it works for you.
Hi @chaley,

Could you please create a similar template to search for each author that has a Link and return only one book per author?
Comfy.n is offline   Reply With Quote