|  05-07-2024, 04:29 PM | #1 | 
| Junior Member  Posts: 6 Karma: 10 Join Date: May 2024 Device: Kindle Paperwhite (11th Generation) | 
				
				Save to Disk Template Issue with Series vs Standalone
			 
			
			I have a Save to Disk template that seems like it should work; however, is throwing an error when actually running the task. It does work successfully for books with a series, but fails on the standalones with the following error. Code: Traceback (most recent call last):
      File "calibre\library\save_to_disk.py", line 282, in get_path_components
      File "calibre\library\save_to_disk.py", line 247, in get_components
      File "calibre\utils\formatter.py", line 1930, in unsafe_format
      File "calibre\utils\formatter.py", line 1847, in evaluate
      File "string.py", line 194, in vformat
      File "string.py", line 203, in _vformat
    ValueError: Single '}' encountered in format string
    
    During handling of the above exception, another exception occurred:
    
    Traceback (most recent call last):
      File "calibre\gui2\save.py", line 139, in do_one_collect
      File "calibre\gui2\save.py", line 147, in collect_data
      File "calibre\library\save_to_disk.py", line 288, in get_path_components
    ValueError: Failed to calculate path for save to disk. Template: {series:'re(ifempty($,field('title') & ' - ' & field('authors')),':',' -')'}/{series:'re(ifempty($,field('title') & ' - ' & field('authors')),':',' -')'}{series_index:0>2s| - | - {title}}
    Error: Single '}' encountered in format string  | 
|   |   | 
|  05-07-2024, 06:36 PM | #2 | |
| Grand Sorcerer            Posts: 12,525 Karma: 8065948 Join Date: Jan 2010 Location: Notts, England Device: Kobo Libra 2 | 
			
			From the Advanced formatting section of the template language manual: Quote: 
 Code: {series_index:0>2s| - | - {title}}Code: {series_index:0>2s| - | - }{title}IMO a template of this complexity should be written in Template Program Mode (TPM). Not only is branching easier, TPM templates are much easier to debug. | |
|   |   | 
| Advert | |
|  | 
|  05-07-2024, 06:38 PM | #3 | 
| Well trained by Cats            Posts: 31,249 Karma: 61360164 Join Date: Aug 2009 Location: The Central Coast of California Device: Kobo Libra2,Kobo Aura2v1, K4NT(Fixed: New Bat.), Galaxy Tab A | 
			
			You did not close series index before  Title { } are always pairs and are not nested | 
|   |   | 
|  05-07-2024, 08:52 PM | #4 | |
| Junior Member  Posts: 6 Karma: 10 Join Date: May 2024 Device: Kindle Paperwhite (11th Generation) | Quote: 
 Library Root ┖── Series Name ┖── Series Name.epub I'll look into the TPM template. | |
|   |   | 
|  05-07-2024, 08:54 PM | #5 | |
| Junior Member  Posts: 6 Karma: 10 Join Date: May 2024 Device: Kindle Paperwhite (11th Generation) | Quote: 
 {series:'re(ifempty($,field('title') & ' - ' & field('authors')),':',' -')'}/{series:'re(ifempty($,field('title') & ' - ' & field('authors')),':',' -')'}{series_index:0>2s| - |} | |
|   |   | 
| Advert | |
|  | 
|  05-07-2024, 09:36 PM | #6 | 
| Junior Member  Posts: 6 Karma: 10 Join Date: May 2024 Device: Kindle Paperwhite (11th Generation) | 
			
			Sorry for the triple post at this point, but I ended up moving to Python because it just made way more sense to me. It's a little bit slower to run, but I'm only occasionally saving books out to disk. Code: python:
def evaluate(book, context):
	if book.series is None:
		author_str = ""
		for author in range(len(book.authors)):
			author_str += book.authors[author]
		book_str = book.title + ' - ' + author_str + '/' + book.title + ' - ' + author_str
	else:
		book_str = book.series + '/' + book.series + ' - ' + f"{int(book.series_index):02}" + ' - ' + book.title
	return book_str | 
|   |   | 
|  05-07-2024, 11:52 PM | #7 | 
| Grand Sorcerer            Posts: 12,525 Karma: 8065948 Join Date: Jan 2010 Location: Notts, England Device: Kobo Libra 2 | 
			
			Your python template smashes all the author names together without separation. Is that what you want? I think you want this: Code: python:
def evaluate(book, context):
	if book.series is None:
		author_str = ' & '.join(book.authors)
		book_str = book.title + ' - ' + author_str + '/' + book.title + ' - ' + author_str
	else:
		book_str = book.series + '/' + book.series + ' - ' + f"{int(book.series_index):02}" + ' - ' + book.title
	return book_strCode: python:
def evaluate(book, context):
	if book.series is None:
		author_str = ' & '.join(book.authors)
		book_str = f'{book.title} - {author_str}/{book.title} - {author_str}'
	else:
		book_str = f'{book.series}/{book.series} - {int(book.series_index):02} - {book.title}'
	return book_strCode: program:
	if $series then
		res = template('{series}/{series} - {series_index:0>2s} - {title}')
	else
		res = template('{title} - {authors}/{title} - {authors}')
	fi;
	resCode: {series_index:0>2.0f} | 
|   |   | 
|  05-08-2024, 12:07 AM | #8 | 
| Junior Member  Posts: 6 Karma: 10 Join Date: May 2024 Device: Kindle Paperwhite (11th Generation) | 
			
			You're absolutely right in that I didn't want the names smashed together. I had actually already fixed that on my side, but didn't want to post a 4th time in a row and didn't see a way to edit my existing post. Appreciate the simplified version and agreed it looks much cleaner. I was mainly just on a kick of adding each piece one at a time and validating the path in the template editor was showing as expected. I don't currently have anything with a decimal in my library, so that's definitely an edge case I didn't consider. I'll manually adjust some metadata and play with that a little bit. I don't think I necessarily care if it's 00.5 vs 0.5. I just think it's cleaner to be 03 vs 3 especially when you get into series that go up into the double digits. | 
|   |   | 
|  05-08-2024, 12:16 AM | #9 | 
| Junior Member  Posts: 6 Karma: 10 Join Date: May 2024 Device: Kindle Paperwhite (11th Generation) | 
			
			Looks like this will handle the decimal series indexes: Code: python:
def evaluate(book, context):
	if book.series is None:
		author_str = ' & '.join(book.authors)
		book_str = f'{book.title} - {author_str}/{book.title} - {author_str}'
	else:
		if book.series_index.is_integer():
			book_str = f'{book.series}/{book.series} - {int(book.series_index):02} - {book.title}'
		else:
			book_str =  f'{book.series}/{book.series} - {book.series_index} - {book.title}'
	return book_str | 
|   |   | 
|  | 
| 
 | 
|  Similar Threads | ||||
| Thread | Thread Starter | Forum | Replies | Last Post | 
| Save to disk title sort order different for series vs standalone books? | threebluestars | Library Management | 0 | 01-06-2020 11:36 PM | 
| Save to Disk Template Help | Tanjamuse | Library Management | 2 | 08-09-2019 09:35 AM | 
| save to disk template help | bilaly | Library Management | 2 | 10-19-2018 07:19 PM | 
| Save to Disk Template with series in brackets | Vortex | Calibre | 18 | 10-12-2018 01:52 PM | 
| Need help - Save to Disk template | Gallips | Calibre | 8 | 06-28-2016 01:46 PM |