View Single Post
Old 07-15-2023, 04:39 AM   #1133
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,482
Karma: 8025704
Join Date: Jan 2010
Location: Notts, England
Device: Kobo Libra 2
Quote:
Originally Posted by capink View Post
If you don't want to modify the values it is better to steer away from SFE. Two solutions spring to mind:
[snip]
I ended up using chain variables and a formula to show output, as you suggested.
Quote:
A solution is not necessarily a new action, it might be a matter of a new template function. While we are at it, is there for a way for a function to know which template mode it is running in, to modify the output depending on the mode. e.g. from_selection() could return a python list instead of a string if running in a python mode.
Code:
utils.formatter_functions.function_object_type(template)
This accepts template text, a stored template, or a template function.
Quote:
Edit: As for errors, you can save them in a global variable, and display them using a Formula Action at the end of the chain. This works for any kind of solution you choose, whether a Formula Action, a Chains Variables Action or even a "Run Python Code" Action.
I ended up building an "example" action chain that I can use as the starting point. It contains two actions: a chain variables action that is run over the selected books, and a formulas action that displays any output.

The chain variables action puts its output into a list stored in globals. It also sets the chain variable "has_output" if there is anything in the list. The formulas action has a condition ensuring the action is run only if "has_output" is set to the non-empty string. The export of the prototype action chain is attached.

Here is the prototype chain variables action:
Code:
python:
def evaluate(book, context):
	# Run the desired template. It must produce a string
	output = run_template(book, context)

	# if the template produced some output, store it in globals to be printed later
	all_output = context.globals.get('output', [])
	if output:
		all_output.append(f'{book.title} ({book.id}): {output}')
		context.globals['output'] = all_output
	return 'yes' if all_output else ''

def run_template(book, context):
	# you can directly enter a python template here, or alternatively call
	# a stored template (GPM or python) or formatter function using
	# context.funcs.name.
	# Example: context.funcs.template('{series:|| [}{series_index:||]}')
	# runs the SFM template to return the series and series index
	return context.funcs.template('{series:|| [}{series_index:||]}')
Here is the formula action. It formats the list of "errors" from the chain vars action into a single string.
Code:
python:
def evaluate(book, context):
	return '\n'.join(context.globals.get('output', ''))
The condition check is equally simple:
Code:
program:
	return globals(has_output) != ''
Here is an example that uses @ownedbycats request, to copy the cover into the data directory for all selected books. At the end it shows a dialog listing the books and whether or not a cover was copied.
Code:
python:
def evaluate(book, context):
	# Run the desired template. It must produce a string
	output = run_template(book, context)

	# if the template produced some output, store it in globals to be printed later
	all_output = context.globals.get('output', [])
	if output:
		all_output.append(f'{book.title} ({book.id}): {output}')
		context.globals['output'] = all_output
	return 'yes' if all_output else ''

def run_template(book, context):
	import os
	from shutil import copy
	from calibre.db.constants import DATA_DIR_NAME

	db = context.db
	cache = db.new_api
	# Get the normalized library path
	library_path = cache.backend.library_path
	
    # Construct the full path to the book folder
	path = os.path.join(library_path, cache.field_for('path', book.id).replace('/', os.sep))

	# Ensure the data directory exists
	data_dir = os.path.join(path, DATA_DIR_NAME)
	if not os.path.exists(data_dir):
		os.mkdir(data_dir)

	cover_file = os.path.join(path, 'cover.jpg')
	if os.path.exists(cover_file):
		# It does. Copy it to the data directory. The 'copy' method takes a
		# directory as a target.
		copy(cover_file, data_dir)
		return 'cover copied'
	return 'cover not copied'
Attached Files
File Type: zip Run template over books prototype.zip (883 Bytes, 721 views)
chaley is offline   Reply With Quote