From b48b5d34c897483c572103a5d5690740d3ac8495 Mon Sep 17 00:00:00 2001 From: Charles Haley Date: Fri, 7 Feb 2025 22:16:31 +0000 Subject: [PATCH] The real work: interpreting the template and putting into links in book details. This code could use some refactoring and more testing. --- src/calibre/ebooks/metadata/book/render.py | 116 ++++++++++++++------- 1 file changed, 78 insertions(+), 38 deletions(-) diff --git a/src/calibre/ebooks/metadata/book/render.py b/src/calibre/ebooks/metadata/book/render.py index 0ccf37240d..11c5ba445d 100644 --- a/src/calibre/ebooks/metadata/book/render.py +++ b/src/calibre/ebooks/metadata/book/render.py @@ -12,6 +12,7 @@ from calibre import force_unicode, prepare_string_for_xml from calibre.constants import filesystem_encoding from calibre.db.constants import DATA_DIR_NAME from calibre.ebooks.metadata import fmt_sidx, rating_to_stars +from calibre.ebooks.metadata.book.formatter import SafeFormat from calibre.ebooks.metadata.search_internet import DEFAULT_AUTHOR_SOURCE, name_for, qquote, url_for_author_search, url_for_book_search from calibre.ebooks.metadata.sources.identify import urls_from_identifiers from calibre.library.comments import comments_to_html, markdown @@ -66,6 +67,19 @@ def search_action_with_data(search_term, value, book_id, field=None, **k): return search_action(search_term, value, field=field, book_id=book_id, **k) +def cc_search_action_with_data(search_term, value, book_id, fm, mi, field=None, **k): + if mi is not None and fm is not None: + template = fm.get('display', {}).get('web_search_template') + if template: + formatter = SafeFormat() + mi.set('item_value', value) + u = formatter.safe_format(template, mi, "BOOK DETAILS WEB LINK", mi) + if u: + v = prepare_string_for_xml(_('Click to browse to {0}').format(u), attribute=True) + return action('cc_url', url=u),v + t = _('Click to see books with {0}: {1}').format(mi.get('name', search_term), prepare_string_for_xml(value)) + return search_action_with_data(search_term, value, book_id, **k), t + def notes_action(**keys): return 'notes:' + as_hex_unicode(json_dumps(keys)) @@ -211,16 +225,16 @@ def mi_to_html( ans.append((field, row % (name, comments_to_html(val)))) else: if not metadata['is_multiple']: - val = '{}'.format( - search_action(field, val, book_id=book_id), - _('Click to see books with {0}: {1}').format(metadata['name'], a(val)), p(val)) + u,v = cc_search_action_with_data(field, val, book_id, metadata, mi, field) + val = '{}'.format(u, v, p(val)) else: all_vals = [v.strip() for v in val.split(metadata['is_multiple']['cache_to_list']) if v.strip()] if show_links: - links = ['{}'.format( - search_action(field, x, book_id=book_id), _('Click to see books with {0}: {1}').format( - metadata['name'], a(x)), p(x)) for x in all_vals] + links = [] + for x in all_vals: + u,v = cc_search_action_with_data(field, x, book_id, metadata, mi, field) + links.append('{}'.format(u, v, p(x))) else: links = all_vals val = value_list(metadata['is_multiple']['list_to_ui'], links) @@ -349,12 +363,19 @@ def mi_to_html( except Exception: st = field series = getattr(mi, field) - val = _( - '%(sidx)s of ' - '%(series)s') % dict( - sidx=fmt_sidx(sidx, use_roman=use_roman_numbers), cls='series_name', - series=p(series), href=search_action_with_data(st, series, book_id, field), - tt=p(_('Click to see books in this series'))) + if metadata.get('display', {}).get('web_search_template'): + u,v = cc_search_action_with_data(st, series, book_id, metadata, mi, field) + val = _('%(sidx)s of ' + '%(series)s') % dict( + sidx=fmt_sidx(sidx, use_roman=use_roman_numbers), cls='series_name', + series=p(series), href=u, tt=v) + else: + val = _( + '%(sidx)s of ' + '%(series)s') % dict( + sidx=fmt_sidx(sidx, use_roman=use_roman_numbers), cls='series_name', + series=p(series), href=search_action_with_data(st, series, book_id, field), + tt=p(_('Click to see books in this series'))) val += add_other_links(field, series) elif metadata['datatype'] == 'datetime': aval = getattr(mi, field) @@ -371,32 +392,51 @@ def mi_to_html( search_action_with_data(key, str(aval), book_id, None, original_value=val), a( _('Click to see books with {0}: {1} (derived from {2})').format( metadata['name'] or field, aval, val)), val) - elif metadata['datatype'] == 'text' and metadata['is_multiple']: - try: - st = metadata['search_terms'][0] - except Exception: - st = field - all_vals = mi.get(field) - if not metadata.get('display', {}).get('is_names', False): - all_vals = sorted(all_vals, key=sort_key) - links = [] - for x in all_vals: - v = '{}'.format( - search_action_with_data(st, x, book_id, field), _('Click to see books with {0}: {1}').format( - metadata['name'] or field, a(x)), p(x)) - v += add_other_links(field, x) - links.append(v) - val = value_list(metadata['is_multiple']['list_to_ui'], links) - elif metadata['datatype'] == 'text' or metadata['datatype'] == 'enumeration': - # text/is_multiple handled above so no need to add the test to the if - try: - st = metadata['search_terms'][0] - except Exception: - st = field - v = '{}'.format( - search_action_with_data(st, unescaped_val, book_id, field), a( - _('Click to see books with {0}: {1}').format(metadata['name'] or field, val)), val) - val = v + add_other_links(field, val) + elif metadata['datatype'] == 'text': + if metadata['is_multiple']: + try: + st = metadata['search_terms'][0] + except Exception: + st = field + all_vals = mi.get(field) + if not metadata.get('display', {}).get('is_names', False): + all_vals = sorted(all_vals, key=sort_key) + links = [] + if show_links: + for x in all_vals: + if metadata['is_custom']: + u,v = cc_search_action_with_data(field, x, book_id, metadata, mi, field) + v = '{}'.format(u, v, p(x)) + else: + v = '{}'.format( + search_action_with_data(st, x, book_id, field), + _('Click to see books with {0}: {1}').format( + metadata['name'] or field, a(x)), p(x)) + v += add_other_links(field, x) + links.append(v) + else: + links = all_vals + val = value_list(metadata['is_multiple']['list_to_ui'], links) + else: + try: + st = metadata['search_terms'][0] + except Exception: + st = field + if show_links: + if metadata['is_custom']: + u,v = cc_search_action_with_data(st, x, book_id, metadata, mi, field) + v = '{}'.format(u, v, p(x)) + else: + v = '{}'.format( + search_action_with_data(st, x, book_id, field), + _('Click to see books with {0}: {1}').format( + metadata['name'] or field, a(x)), p(x)) + else: + v = val + val = v + add_other_links(field, val) + elif metadata['datatype'] == 'enumeration': + u,v = cc_search_action_with_data(field, x, book_id, metadata, mi, field) + val = '{}'.format(u, v, p(x)) + add_other_links(field, val) elif metadata['datatype'] == 'bool': val = '{}'.format( search_action_with_data(field, val, book_id, None), a(