This commit is contained in:
Kovid Goyal 2022-11-15 19:33:51 +05:30
commit 19ffac569e
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C

View File

@ -17,7 +17,7 @@ version = 0 # change this if you change signature of implementation()
FIELDS = { FIELDS = {
'title', 'authors', 'author_sort', 'publisher', 'rating', 'timestamp', 'size', 'title', 'authors', 'author_sort', 'publisher', 'rating', 'timestamp', 'size',
'tags', 'comments', 'series', 'series_index', 'formats', 'isbn', 'uuid', 'tags', 'comments', 'series', 'series_index', 'formats', 'isbn', 'uuid',
'pubdate', 'cover', 'last_modified', 'identifiers', 'languages' 'pubdate', 'cover', 'last_modified', 'identifiers', 'languages', 'template'
} }
@ -33,9 +33,14 @@ def cover(db, book_id):
def implementation( def implementation(
db, notify_changes, fields, sort_by, ascending, search_text, limit db, notify_changes, fields, sort_by, ascending, search_text, limit, template=None
): ):
is_remote = notify_changes is not None is_remote = notify_changes is not None
if 'template' in fields:
# Yes, this leaves formatter undefined if template isn't a field but
# that isn't a problem with the current implementation
from calibre.ebooks.metadata.book.formatter import SafeFormat
formatter = SafeFormat()
with db.safe_read_lock: with db.safe_read_lock:
fm = db.field_metadata fm = db.field_metadata
afields = set(FIELDS) | {'id'} afields = set(FIELDS) | {'id'}
@ -64,6 +69,15 @@ def implementation(
x = db.all_field_for('identifiers', book_ids, default_value={}) x = db.all_field_for('identifiers', book_ids, default_value={})
data[field] = {k: v.get('isbn') or '' for k, v in iteritems(x)} data[field] = {k: v.get('isbn') or '' for k, v in iteritems(x)}
continue continue
if field == 'template':
vals = {}
globals = {}
for book_id in book_ids:
mi = db.get_proxy_metadata(book_id)
vals[book_id] = formatter.safe_format(template, {}, 'TEMPLATE ERROR',
mi, global_vars=globals)
data['template'] = vals
continue
field = field.replace('*', '#') field = field.replace('*', '#')
metadata[field] = fm[field] metadata[field] = fm[field]
if not is_remote: if not is_remote:
@ -140,10 +154,21 @@ def do_list(
separator, separator,
prefix, prefix,
limit, limit,
template,
template_file,
template_title,
for_machine=False for_machine=False
): ):
if sort_by is None: if sort_by is None:
ascending = True ascending = True
if 'template' in [f.strip() for f in fields]:
if template_file:
with lopen(template_file, 'rb') as f:
template = f.read().decode('utf-8')
if not template:
raise SystemExit(_('You must provide a template'))
ans = dbctx.run('list', fields, sort_by, ascending, search_text, limit, template)
else:
ans = dbctx.run('list', fields, sort_by, ascending, search_text, limit) ans = dbctx.run('list', fields, sort_by, ascending, search_text, limit)
try: try:
book_ids, data, metadata = ans['book_ids'], ans['data'], ans['metadata'] book_ids, data, metadata = ans['book_ids'], ans['data'], ans['metadata']
@ -196,7 +221,7 @@ def do_list(
widths = list(base_widths) widths = list(base_widths)
titles = map( titles = map(
lambda x, y: '%-*s%s' % (x - len(separator), y, separator), widths, lambda x, y: '%-*s%s' % (x - len(separator), y, separator), widths,
fields [template_title if v == 'template' else v for v in fields]
) )
with ColoredStream(sys.stdout, fg='green'): with ColoredStream(sys.stdout, fg='green'):
print(''.join(titles), flush=True) print(''.join(titles), flush=True)
@ -207,11 +232,11 @@ def do_list(
for record in output_table: for record in output_table:
text = [ text = [
wrappers[i](record[i]) for i, field in enumerate(fields) wrappers[i](record[i]) for i, _ in enumerate(fields)
] ]
lines = max(map(len, text)) lines = max(map(len, text))
for l in range(lines): for l in range(lines):
for i, field in enumerate(text): for i, _ in enumerate(text):
ft = text[i][l] if l < len(text[i]) else '' ft = text[i][l] if l < len(text[i]) else ''
stdout.write(ft.encode('utf-8')) stdout.write(ft.encode('utf-8'))
if i < len(text) - 1: if i < len(text) - 1:
@ -262,8 +287,9 @@ List the books available in the calibre database.
'--search', '--search',
default=None, default=None,
help=_( help=_(
'Filter the results by the search query. For the format of the search query,' 'Filter the results by the search query. For the format of the search '
' please see the search related documentation in the User Manual. Default is to do no filtering.' 'query, please see the search related documentation in the User '
'Manual. Default is to do no filtering.'
) )
) )
parser.add_option( parser.add_option(
@ -298,9 +324,28 @@ List the books available in the calibre database.
default=False, default=False,
action='store_true', action='store_true',
help=_( help=_(
'Generate output in JSON format, which is more suitable for machine parsing. Causes the line width and separator options to be ignored.' 'Generate output in JSON format, which is more suitable for machine '
'parsing. Causes the line width and separator options to be ignored.'
) )
) )
parser.add_option(
'--template',
default=None,
help=_('The template to run if "{}" is in the field list. Default: None').format('template')
)
parser.add_option(
'--template_file',
'-t',
default=None,
help=_('Path to a file containing the template to run if "{}" is in '
'the field list. Default: None').format('template')
)
parser.add_option(
'--template_heading',
default='template',
help=_('Heading for the template column. Default: %default. This option '
'is ignored if the option {} is set').format('--for-machine')
)
return parser return parser
@ -322,6 +367,9 @@ def main(opts, args, dbctx):
opts.separator, opts.separator,
opts.prefix, opts.prefix,
opts.limit, opts.limit,
opts.template,
opts.template_file,
opts.template_heading,
for_machine=opts.for_machine for_machine=opts.for_machine
) )
return 0 return 0