View Single Post
Old 03-27-2016, 06:21 PM   #732
JJanssen
Member
JJanssen began at the beginning.
 
Posts: 16
Karma: 24
Join Date: Jun 2009
Device: Kindle Paperwhite 1
Quote:
Originally Posted by eschwartz View Post
You can simply include the GPM template directly in the plugboard definition. Right-click and there will be an option to use the Template Editor.
(When saved, it appears as if it is one line, but internally linebreaks are still saved as '\n' -- also, linebreaks may help you read it but they don't affect the parsing.)
I just found out there was such a thing as a template editor right before I read your message. Apparently it's even possible to change the template on a custom column without restarting Calibre! Who knew. Anyway. That's jsut my struggle with some UI bits.

Quote:
Again, you just need to feed finish_formatting() with the formatting specification in the custom column.

Code:
{series_index:0>5.2f| – | – }
becomes
Code:
finish_formatting(field('#series'), field('#format_str'), ' – ', ' – ')
Okay, so that'd become something like
Code:
program:
strcat(
	field('series'),
	finish_formatting(field('series_index'), field('#format_str'), ' – ', ' – '),
	field('title')
)
, right? And that *almost* works, except that the template really doesn't like actually doing that finish_formatting operation -- "TEMPLATE ERROR unknown format code 'f' for object of type unicode". That was when I moved on to the extra column because that's what the docs seemed to imply.

Hardcoding a format..... right. wait. What that function expects is apparently "05.1f", not "{0:05.1f}". So it might work if I simplified the generating script a little.

Yup.

That does the trick.

So just for documentation purposes, here's my working setup:
Spoiler:


Intention: Series indexes will get a fixed number of digits before the decimal point, filled out with 0s in front whenever necessary. Those books with Integer indexes will get just those as index, and those books in a series that have a fractional index will get those with a number of digits after the decimal point that is also the same per series.

For instance, a series with a couple of fractional books, and mostly just lots of them, might get numbered:
Code:
001
001.5
002
003
003.1
003.2
[...]
011
013.3
801
802
803
803.2

The script to generate the custom formatting column:
Code:
def init_cache(library_path = None):
	from calibre.db.backend import DB
	from calibre.db.cache import Cache
	from calibre.utils.config import prefs
	if library_path == None:
		library_path = prefs['library_path']
	backend = DB(library_path)
	cache = Cache(backend)
	cache.init()
	return cache

cache = init_cache()
#cache = init_cache('/Users/jasper/Documents/Calibre Main Library/')
#cache = init_cache(library_path = '/Users/jasper/Documents/Calibre Test Library/')
#
# The parameter can be empty, for the currently opened library, 
# or you can pass a specific Library's path if you wish.
#
#-------------------- Usage specific code starts here ------------------

import math
from collections import defaultdict


series_info = defaultdict(dict)
fract_ids = []

for id_ in cache.all_book_ids():
	series = cache.field_for('series', id_)
	if series:
		sidx = cache.field_for('series_index', id_)
		str_sidx = str(sidx)
		components = str_sidx.split('.')
		if components[1] == '0':
			fract_part = 0
		else:
			fract_part = len(components[1])
			fract_ids.append(id_)
		val_part = len(components[0])
		series_info[series]['val_part'] = max(series_info[series].get('val_part', 0), val_part)
		series_info[series]['fract_part'] = max(series_info[series].get('fract_part', 0), fract_part)
		
for series,sinfo in series_info.iteritems():
	fract_part = sinfo['fract_part']
#	if fract_part == 1:  # Once fractional parts come into play, always have them at least 2 long.
#		fract_part = 2  # Not sure yet if I actually want that.
	print "Series name:",series
	brief_format_str = '0%d.0f'%(sinfo['val_part'])
	print "Format String for books without fraction:",brief_format_str
	if fract_part > 0:
		full_format_str = '0%d.%df'%(sinfo['val_part'] + fract_part + (1 if fract_part > 0 else 0), fract_part)
		print "Format string for books with fraction:",full_format_str
	sids = cache.search('series:"=' + series + '"')
	dct = {}
	for book_id in sids:
		if book_id in fract_ids:
			dct[book_id] = full_format_str
		else:
			dct[book_id] = brief_format_str
	cache.set_field('#format_str', dct)
(I've left in just a couple of the debug prints because, well, I think they're useful)
Custom column #format_str stores the format str, custom column #series_index_formatted stores the formatted series index, templated as
Code:
program:
	finish_formatting(field('series_index'), field("#format_str"),'','')
, and the plugboard then becomes
Code:
{series}{#series_index_formatted:| - | - }{title}
(The added templated column may or may not impact the performance in my usecase -- I'm betting not -- but I think the extra elegance of the system as a whole probably is worth it anyway.)


So, wow, that was definitely one of those cases where I was looking for the issue in all the wrong places. Sorry for trying your patience! And definitely thanks for pointing me in the right direction.

Last edited by JJanssen; 05-01-2016 at 06:45 AM. Reason: I accidentally the plugboard template wrong.
JJanssen is offline   Reply With Quote