1
0
mirror of https://github.com/janeczku/calibre-web synced 2024-09-21 03:39:46 +00:00

Improvements merge metadata upload format

Music icon only visible once if more than one audio format available
This commit is contained in:
Ozzie Isaacs 2024-08-18 16:27:02 +02:00
parent 0f9b5d08e9
commit 6717683ac3
13 changed files with 90 additions and 85 deletions

View File

@ -455,13 +455,13 @@ def do_edit_book(book_id, upload_formats=None):
# Update folder of book on local disk # Update folder of book on local disk
edited_books_id = None edited_books_id = None
title_author_error = None title_author_error = None
upload_format = False upload_mode = False
# handle book title change # handle book title change
if "book_title" in to_save: if "title" in to_save:
title_change = handle_title_on_edit(book, to_save["book_title"]) title_change = handle_title_on_edit(book, to_save["title"])
# handle book author change # handle book author change
if not upload_formats: if not upload_formats:
input_authors, author_change = handle_author_on_edit(book, to_save["author_name"]) input_authors, author_change = handle_author_on_edit(book, to_save["authors"])
if author_change or title_change: if author_change or title_change:
edited_books_id = book.id edited_books_id = book.id
modify_date = True modify_date = True
@ -475,10 +475,9 @@ def do_edit_book(book_id, upload_formats=None):
# handle book ratings # handle book ratings
modify_date |= edit_book_ratings(to_save, book) modify_date |= edit_book_ratings(to_save, book)
meta = True
else: else:
# handle upload other formats from local disk # handle upload other formats from local disk
to_save, upload_format = upload_book_formats(upload_formats, book, book_id, book.has_cover) to_save, edit_error = upload_book_formats(upload_formats, book, book_id, book.has_cover)
# handle upload covers from local disk # handle upload covers from local disk
cover_upload_success = upload_cover(request, book) cover_upload_success = upload_cover(request, book)
if cover_upload_success or to_save.get("format_cover"): if cover_upload_success or to_save.get("format_cover"):
@ -507,7 +506,7 @@ def do_edit_book(book_id, upload_formats=None):
# Add default series_index to book # Add default series_index to book
modify_date |= edit_book_series_index(to_save.get("series_index"), book) modify_date |= edit_book_series_index(to_save.get("series_index"), book)
# Handle book comments/description # Handle book comments/description
modify_date |= edit_book_comments(Markup(to_save.get('description')).unescape(), book) modify_date |= edit_book_comments(Markup(to_save.get('comments')).unescape(), book)
# Handle identifiers # Handle identifiers
input_identifiers = identifier_list(to_save, book) input_identifiers = identifier_list(to_save, book)
modification, warning = modify_identifiers(input_identifiers, book.identifiers, calibre_db.session) modification, warning = modify_identifiers(input_identifiers, book.identifiers, calibre_db.session)
@ -522,7 +521,12 @@ def do_edit_book(book_id, upload_formats=None):
modify_date |= edit_book_publisher(to_save.get('publisher'), book) modify_date |= edit_book_publisher(to_save.get('publisher'), book)
# handle book languages # handle book languages
try: try:
modify_date |= edit_book_languages(to_save.get('languages'), book, upload_format) invalid = []
modify_date |= edit_book_languages(to_save.get('languages'), book, upload_mode=upload_formats,
invalid=invalid)
if invalid:
for lang in invalid:
flash(_("'%(langname)s' is not a valid language", langname=lang), category="warning")
except ValueError as e: except ValueError as e:
flash(str(e), category="error") flash(str(e), category="error")
edit_error = True edit_error = True
@ -549,9 +553,7 @@ def do_edit_book(book_id, upload_formats=None):
calibre_db.session.commit() calibre_db.session.commit()
if config.config_use_google_drive: if config.config_use_google_drive:
gdriveutils.updateGdriveCalibreFromLocal() gdriveutils.updateGdriveCalibreFromLocal()
# if format is upladed and something goes wrong to_save is set to empty dictonary if edit_error is not True and title_author_error is not True and cover_upload_success is not False:
if (len(to_save)
and edit_error is not True and title_author_error is not True and cover_upload_success is not False):
flash(_("Metadata successfully updated"), category="success") flash(_("Metadata successfully updated"), category="success")
if upload_formats: if upload_formats:
@ -579,19 +581,20 @@ def do_edit_book(book_id, upload_formats=None):
return redirect(url_for('web.show_book', book_id=book.id)) return redirect(url_for('web.show_book', book_id=book.id))
def merge_metadata(to_save, meta): def merge_metadata(book, meta, to_save):
if not to_save.get("languages") and meta.languages: if meta.cover:
upload_language = True to_save['cover_format'] = meta.cover
else:
upload_language = False
for s_field, m_field in [ for s_field, m_field in [
('tags', 'tags'), ('author_name', 'author'), ('series', 'series'), ('tags', 'tags'), ('authors', 'author'), ('series', 'series'),
('series_index', 'series_id'), ('languages', 'languages'), ('series_index', 'series_id'), ('languages', 'languages'),
('book_title', 'title'), ('description', 'description'),('format_cover', 'cover')]: ('title', 'title'), ('comments', 'description')]:
val = getattr(meta, m_field, '') try:
val = None if len(getattr(book, s_field)) else getattr(meta, m_field, '')
except TypeError:
val = None if len(str(getattr(book, s_field))) else getattr(meta, m_field, '')
if val: if val:
to_save[s_field] = val to_save[s_field] = val
return upload_language
def identifier_list(to_save, book): def identifier_list(to_save, book):
"""Generate a list of Identifiers from form information""" """Generate a list of Identifiers from form information"""
@ -1054,10 +1057,7 @@ def edit_book_languages(languages, book, upload_mode=False, invalid=None):
if languages: if languages:
input_languages = languages.split(',') input_languages = languages.split(',')
unknown_languages = [] unknown_languages = []
if not upload_mode: input_l = isoLanguages.get_language_code_from_name(get_locale(), input_languages, unknown_languages)
input_l = isoLanguages.get_language_codes(get_locale(), input_languages, unknown_languages)
else:
input_l = isoLanguages.get_valid_language_codes(get_locale(), input_languages, unknown_languages)
for lang in unknown_languages: for lang in unknown_languages:
log.error("'%s' is not a valid language", lang) log.error("'%s' is not a valid language", lang)
if isinstance(invalid, list): if isinstance(invalid, list):
@ -1071,7 +1071,7 @@ def edit_book_languages(languages, book, upload_mode=False, invalid=None):
if input_l[0] != current_user.filter_language() and current_user.filter_language() != "all": if input_l[0] != current_user.filter_language() and current_user.filter_language() != "all":
input_l[0] = calibre_db.session.query(db.Languages). \ input_l[0] = calibre_db.session.query(db.Languages). \
filter(db.Languages.lang_code == current_user.filter_language()).first().lang_code filter(db.Languages.lang_code == current_user.filter_language()).first().lang_code
# Remove duplicates # Remove duplicates from normalized langcodes
input_l = helper.uniq(input_l) input_l = helper.uniq(input_l)
return modify_database_object(input_l, book.languages, db.Languages, calibre_db.session, 'languages') return modify_database_object(input_l, book.languages, db.Languages, calibre_db.session, 'languages')
return False return False
@ -1200,37 +1200,35 @@ def edit_cc_data(book_id, book, to_save, cc):
return changed return changed
# returns None if no file is uploaded # returns False if an error occurs or no book is uploaded, in all other cases the ebook metadata to change is returned
# returns False if an error occurs, in all other cases the ebook metadata is returned
def upload_book_formats(requested_files, book, book_id, no_cover=True): def upload_book_formats(requested_files, book, book_id, no_cover=True):
# Check and handle Uploaded file # Check and handle Uploaded file
to_save = dict() to_save = dict()
upload_format = False error = False
allowed_extensions = config.config_upload_formats.split(',') allowed_extensions = config.config_upload_formats.split(',')
for requested_file in requested_files: for requested_file in requested_files:
current_filename = requested_file.filename current_filename = requested_file.filename
if config.config_check_extensions and allowed_extensions != ['']: if config.config_check_extensions and allowed_extensions != ['']:
if not validate_mime_type(requested_file, allowed_extensions): if not validate_mime_type(requested_file, allowed_extensions):
flash(_("File type isn't allowed to be uploaded to this server"), category="error") flash(_("File type isn't allowed to be uploaded to this server"), category="error")
error = True
continue continue
# return False
# check for empty request
if current_filename != '': if current_filename != '':
if not current_user.role_upload(): if not current_user.role_upload():
flash(_("User has no rights to upload additional file formats"), category="error") flash(_("User has no rights to upload additional file formats"), category="error")
error = True
continue continue
# return False
if '.' in current_filename: if '.' in current_filename:
file_ext = current_filename.rsplit('.', 1)[-1].lower() file_ext = current_filename.rsplit('.', 1)[-1].lower()
if file_ext not in allowed_extensions and '' not in allowed_extensions: if file_ext not in allowed_extensions and '' not in allowed_extensions:
flash(_("File extension '%(ext)s' is not allowed to be uploaded to this server", ext=file_ext), flash(_("File extension '%(ext)s' is not allowed to be uploaded to this server", ext=file_ext),
category="error") category="error")
error = True
continue continue
# return False
else: else:
flash(_('File to be uploaded must have an extension'), category="error") flash(_('File to be uploaded must have an extension'), category="error")
error = True
continue continue
# return False
file_name = book.path.rsplit('/', 1)[-1] file_name = book.path.rsplit('/', 1)[-1]
filepath = os.path.normpath(os.path.join(config.get_book_path(), book.path)) filepath = os.path.normpath(os.path.join(config.get_book_path(), book.path))
@ -1243,14 +1241,14 @@ def upload_book_formats(requested_files, book, book_id, no_cover=True):
except OSError: except OSError:
flash(_("Failed to create path %(path)s (Permission denied).", path=filepath), flash(_("Failed to create path %(path)s (Permission denied).", path=filepath),
category="error") category="error")
error = True
continue continue
# return False
try: try:
requested_file.save(saved_filename) requested_file.save(saved_filename)
except OSError: except OSError:
flash(_("Failed to store file %(file)s.", file=saved_filename), category="error") flash(_("Failed to store file %(file)s.", file=saved_filename), category="error")
error = True
continue continue
# return False
file_size = os.path.getsize(saved_filename) file_size = os.path.getsize(saved_filename)
@ -1268,8 +1266,8 @@ def upload_book_formats(requested_files, book, book_id, no_cover=True):
log.error_or_exception("Database error: {}".format(e)) log.error_or_exception("Database error: {}".format(e))
flash(_("Oops! Database Error: %(error)s.", error=e.orig if hasattr(e, "orig") else e), flash(_("Oops! Database Error: %(error)s.", error=e.orig if hasattr(e, "orig") else e),
category="error") category="error")
error = True
continue continue
# return False # return redirect(url_for('web.show_book', book_id=book.id))
# Queue uploader info # Queue uploader info
link = '<a href="{}">{}</a>'.format(url_for('web.show_book', book_id=book.id), escape(book.title)) link = '<a href="{}">{}</a>'.format(url_for('web.show_book', book_id=book.id), escape(book.title))
@ -1280,8 +1278,13 @@ def upload_book_formats(requested_files, book, book_id, no_cover=True):
*os.path.splitext(current_filename), *os.path.splitext(current_filename),
rar_executable=config.config_rarfile_location, rar_executable=config.config_rarfile_location,
no_cover=no_cover) no_cover=no_cover)
upload_format |= merge_metadata(to_save, meta) merge_metadata(book, meta, to_save)
return to_save if len(to_save) else False, upload_format if to_save.get('languages'):
langs = []
for lang_code in to_save['languages']:
langs.append(isoLanguages.get_language_name(get_locale(), lang_code))
to_save['languages'] = ",".join(langs)
return to_save, error
def upload_cover(cover_request, book): def upload_cover(cover_request, book):
@ -1315,7 +1318,6 @@ def handle_title_on_edit(book, book_title):
def handle_author_on_edit(book, author_name, update_stored=True): def handle_author_on_edit(book, author_name, update_stored=True):
change = False change = False
# handle author(s)
input_authors = prepare_authors(author_name, config.get_book_path(), config.config_use_google_drive) input_authors = prepare_authors(author_name, config.get_book_path(), config.config_use_google_drive)
# Search for each author if author is in database, if not, author name and sorted author name is generated new # Search for each author if author is in database, if not, author name and sorted author name is generated new
@ -1345,7 +1347,6 @@ def search_objects_remove(db_book_object, db_type, input_elements):
if db_type == 'custom': if db_type == 'custom':
type_elements = c_elements.value type_elements = c_elements.value
else: else:
# type_elements = c_elements.name
type_elements = c_elements type_elements = c_elements
for inp_element in input_elements: for inp_element in input_elements:
if type_elements == inp_element: if type_elements == inp_element:

View File

@ -18,6 +18,7 @@
from .iso_language_names import LANGUAGE_NAMES as _LANGUAGE_NAMES from .iso_language_names import LANGUAGE_NAMES as _LANGUAGE_NAMES
from . import logger from . import logger
from .string_helper import strip_whitespaces
log = logger.create() log = logger.create()
@ -69,20 +70,20 @@ def get_language_name(locale, lang_code):
return name return name
def get_language_codes(locale, language_names, remainder=None): def get_language_code_from_name(locale, language_names, remainder=None):
language_names = set(x.strip().lower() for x in language_names if x) language_names = set(strip_whitespaces(x).lower() for x in language_names if x)
lang = list() lang = list()
for k, v in get_language_names(locale).items(): for key, val in get_language_names(locale).items():
v = v.lower() val = val.lower()
if v in language_names: if val in language_names:
lang.append(k) lang.append(key)
language_names.remove(v) language_names.remove(val)
if remainder is not None and language_names: if remainder is not None and language_names:
remainder.extend(language_names) remainder.extend(language_names)
return lang return lang
def get_valid_language_codes(locale, language_names, remainder=None): def get_valid_language_codes_from_code(locale, language_names, remainder=None):
lang = list() lang = list()
if "" in language_names: if "" in language_names:
language_names.remove("") language_names.remove("")

View File

@ -27,7 +27,7 @@ import datetime
import mimetypes import mimetypes
from uuid import uuid4 from uuid import uuid4
from flask import Blueprint, request, url_for from flask import Blueprint, request, url_for, g
from flask_babel import format_date from flask_babel import format_date
from .cw_login import current_user from .cw_login import current_user
@ -182,3 +182,12 @@ def get_cover_srcset(series):
url = url_for('web.get_series_cover', series_id=series.id, resolution=shortname, c=cache_timestamp()) url = url_for('web.get_series_cover', series_id=series.id, resolution=shortname, c=cache_timestamp())
srcset.append(f'{url} {resolution}x') srcset.append(f'{url} {resolution}x')
return ', '.join(srcset) return ', '.join(srcset)
@jinjia.app_template_filter('music')
def contains_music(book_formats):
result = False
for format in book_formats:
if format.format.lower() in g.constants.EXTENSIONS_AUDIO:
result = True
return result

View File

@ -258,14 +258,14 @@ def render_adv_search_results(term, offset=None, order=None, limit=None):
tags['include_' + element] = term.get('include_' + element) tags['include_' + element] = term.get('include_' + element)
tags['exclude_' + element] = term.get('exclude_' + element) tags['exclude_' + element] = term.get('exclude_' + element)
author_name = term.get("author_name") author_name = term.get("authors")
book_title = term.get("book_title") book_title = term.get("title")
publisher = term.get("publisher") publisher = term.get("publisher")
pub_start = term.get("publishstart") pub_start = term.get("publishstart")
pub_end = term.get("publishend") pub_end = term.get("publishend")
rating_low = term.get("ratinghigh") rating_low = term.get("ratinghigh")
rating_high = term.get("ratinglow") rating_high = term.get("ratinglow")
description = term.get("comment") description = term.get("comments")
read_status = term.get("read_status") read_status = term.get("read_status")
if author_name: if author_name:
author_name = strip_whitespaces(author_name).lower().replace(',', '|') author_name = strip_whitespaces(author_name).lower().replace(',', '|')

View File

@ -3,9 +3,9 @@
*/ */
/* global Bloodhound, language, Modernizr, tinymce, getPath */ /* global Bloodhound, language, Modernizr, tinymce, getPath */
if ($("#description").length) { if ($("#comments").length) {
tinymce.init({ tinymce.init({
selector: "#description", selector: "#comments",
plugins: 'code', plugins: 'code',
branding: false, branding: false,
menubar: "edit view format", menubar: "edit view format",
@ -261,8 +261,8 @@ $("#btn-upload-cover").on("change", function () {
$("#xchange").click(function () { $("#xchange").click(function () {
this.blur(); this.blur();
var title = $("#book_title").val(); var title = $("#title").val();
$("#book_title").val($("#bookAuthor").val()); $("#title").val($("#bookAuthor").val());
$("#bookAuthor").val(title); $("#bookAuthor").val(title);
}); });

View File

@ -38,12 +38,12 @@ $(function () {
} }
function populateForm (book) { function populateForm (book) {
tinymce.get("description").setContent(book.description); tinymce.get("comments").setContent(book.comments);
var uniqueTags = getUniqueValues('tags', book) var uniqueTags = getUniqueValues('tags', book)
var uniqueLanguages = getUniqueValues('languages', book) var uniqueLanguages = getUniqueValues('languages', book)
var ampSeparatedAuthors = (book.authors || []).join(" & "); var ampSeparatedAuthors = (book.authors || []).join(" & ");
$("#bookAuthor").val(ampSeparatedAuthors); $("#bookAuthor").val(ampSeparatedAuthors);
$("#book_title").val(book.title); $("#title").val(book.title);
$("#tags").val(uniqueTags.join(", ")); $("#tags").val(uniqueTags.join(", "));
$("#languages").val(uniqueLanguages.join(", ")); $("#languages").val(uniqueLanguages.join(", "));
$("#rating").data("rating").setValue(Math.round(book.rating)); $("#rating").data("rating").setValue(Math.round(book.rating));
@ -172,7 +172,7 @@ $(function () {
$("#get_meta").click(function () { $("#get_meta").click(function () {
populate_provider(); populate_provider();
var bookTitle = $("#book_title").val(); var bookTitle = $("#title").val();
$("#keyword").val(bookTitle); $("#keyword").val(bookTitle);
keyword = bookTitle; keyword = bookTitle;
doSearch(bookTitle); doSearch(bookTitle);

View File

@ -62,11 +62,9 @@
<a class="author-name" href="{{url_for('web.books_list', data='author', sort_param='stored', book_id=author.id) }}">{{author.name.replace('|',',')|shortentitle(30)}}</a> <a class="author-name" href="{{url_for('web.books_list', data='author', sort_param='stored', book_id=author.id) }}">{{author.name.replace('|',',')|shortentitle(30)}}</a>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% for format in entry.Books.data %} {% if entry.Books.data|music %}
{% if format.format|lower in g.constants.EXTENSIONS_AUDIO %}
<span class="glyphicon glyphicon-music"></span> <span class="glyphicon glyphicon-music"></span>
{% endif %} {% endif %}
{% endfor %}
</p> </p>
{% if entry.Books.series.__len__() > 0 %} {% if entry.Books.series.__len__() > 0 %}
<p class="series"> <p class="series">

View File

@ -68,20 +68,20 @@
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"> <input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<div class="col-sm-9 col-xs-12"> <div class="col-sm-9 col-xs-12">
<div class="form-group"> <div class="form-group">
<label for="book_title">{{_('Book Title')}}</label> <label for="title">{{_('Book Title')}}</label>
<input type="text" class="form-control" name="book_title" id="book_title" value="{{book.title}}"> <input type="text" class="form-control" name="title" id="title" value="{{book.title}}">
</div> </div>
<div class="text-center"> <div class="text-center">
<button type="button" class="btn btn-default" id="xchange" ><span class="glyphicon glyphicon-arrow-up"></span><span class="glyphicon glyphicon-arrow-down"></span></button> <button type="button" class="btn btn-default" id="xchange" ><span class="glyphicon glyphicon-arrow-up"></span><span class="glyphicon glyphicon-arrow-down"></span></button>
</div> </div>
<div id="author_div" class="form-group"> <div id="author_div" class="form-group">
<label for="bookAuthor">{{_('Author')}}</label> <label for="bookAuthor">{{_('Author')}}</label>
<input type="text" class="form-control typeahead" autocomplete="off" name="author_name" id="bookAuthor" value="{{' & '.join(authors)}}"> <input type="text" class="form-control typeahead" autocomplete="off" name="authors" id="authors" value="{{' & '.join(authors)}}">
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="description">{{_('Description')}}</label> <label for="comments">{{_('Description')}}</label>
<textarea class="form-control" name="description" id="description" rows="7">{% if book.comments %}{{book.comments[0].text}}{%endif%}</textarea> <textarea class="form-control" name="comments" id="comments" rows="7">{% if book.comments %}{{book.comments[0].text}}{%endif%}</textarea>
</div> </div>
<div class="form-group"> <div class="form-group">
@ -296,7 +296,7 @@
'no_result': {{_('No Result(s) found! Please try another keyword.')|safe|tojson}}, 'no_result': {{_('No Result(s) found! Please try another keyword.')|safe|tojson}},
'author': {{_('Author')|safe|tojson}}, 'author': {{_('Author')|safe|tojson}},
'publisher': {{_('Publisher')|safe|tojson}}, 'publisher': {{_('Publisher')|safe|tojson}},
'description': {{_('Description')|safe|tojson}}, 'comments': {{_('Description')|safe|tojson}},
'source': {{_('Source')|safe|tojson}}, 'source': {{_('Source')|safe|tojson}},
}; };
var language = '{{ current_user.locale }}'; var language = '{{ current_user.locale }}';

View File

@ -15,6 +15,6 @@
<img <img
srcset="{{ srcset }}" srcset="{{ srcset }}"
src="{{ url_for('web.get_series_cover', series_id=series.id, resolution='og', c='day'|cache_timestamp) }}" src="{{ url_for('web.get_series_cover', series_id=series.id, resolution='og', c='day'|cache_timestamp) }}"
alt="{{ book_title }}" alt="{{ title }}"
/> />
{%- endmacro %} {%- endmacro %}

View File

@ -119,11 +119,9 @@
<a class="author-name" href="{{url_for('web.books_list', data='author', book_id=author.id, sort_param='stored') }}">{{author.name.replace('|',',')|shortentitle(30)}}</a> <a class="author-name" href="{{url_for('web.books_list', data='author', book_id=author.id, sort_param='stored') }}">{{author.name.replace('|',',')|shortentitle(30)}}</a>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% for format in entry.Books.data %} {% if entry.Books.data|music %}
{% if format.format|lower in g.constants.EXTENSIONS_AUDIO %}
<span class="glyphicon glyphicon-music"></span> <span class="glyphicon glyphicon-music"></span>
{% endif %} {% endif %}
{%endfor%}
</p> </p>
{% if entry.Books.series.__len__() > 0 %} {% if entry.Books.series.__len__() > 0 %}
<p class="series"> <p class="series">

View File

@ -73,11 +73,9 @@
<a class="author-name" href="{{url_for('web.books_list', data='author', sort_param='stored', book_id=author.id) }}">{{author.name.replace('|',',')|shortentitle(30)}}</a> <a class="author-name" href="{{url_for('web.books_list', data='author', sort_param='stored', book_id=author.id) }}">{{author.name.replace('|',',')|shortentitle(30)}}</a>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% for format in entry.Books.data %} {% if entry.Books.data|music %}
{% if format.format|lower in g.constants.EXTENSIONS_AUDIO %}
<span class="glyphicon glyphicon-music"></span> <span class="glyphicon glyphicon-music"></span>
{% endif %} {% endif %}
{% endfor %}
</p> </p>
{% if entry.Books.series.__len__() > 0 %} {% if entry.Books.series.__len__() > 0 %}
<p class="series"> <p class="series">

View File

@ -5,12 +5,12 @@
<form role="form" id="search" action="{{ url_for('search.advanced_search_form') }}" method="POST"> <form role="form" id="search" action="{{ url_for('search.advanced_search_form') }}" method="POST">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"> <input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<div class="form-group"> <div class="form-group">
<label for="book_title">{{_('Book Title')}}</label> <label for="title">{{_('Book Title')}}</label>
<input type="text" class="form-control" name="book_title" id="book_title" value=""> <input type="text" class="form-control" name="title" id="title" value="">
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="bookAuthor">{{_('Author')}}</label> <label for="bookAuthor">{{_('Author')}}</label>
<input type="text" class="form-control typeahead" name="author_name" id="bookAuthor" value="" autocomplete="off"> <input type="text" class="form-control typeahead" name="authors" id="authors" value="" autocomplete="off">
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="Publisher">{{_('Publisher')}}</label> <label for="Publisher">{{_('Publisher')}}</label>
@ -151,8 +151,8 @@
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="comment">{{_('Description')}}</label> <label for="comments">{{_('Description')}}</label>
<input type="text" class="form-control" name="comment" id="comment" value=""> <input type="text" class="form-control" name="comments" id="comments" value="">
</div> </div>
{% if cc|length > 0 %} {% if cc|length > 0 %}

View File

@ -301,8 +301,8 @@ def get_matching_tags():
q = calibre_db.session.query(db.Books).filter(calibre_db.common_filters(True)) q = calibre_db.session.query(db.Books).filter(calibre_db.common_filters(True))
calibre_db.create_functions() calibre_db.create_functions()
# calibre_db.session.connection().connection.connection.create_function("lower", 1, db.lcase) # calibre_db.session.connection().connection.connection.create_function("lower", 1, db.lcase)
author_input = request.args.get('author_name') or '' author_input = request.args.get('authors') or ''
title_input = request.args.get('book_title') or '' title_input = request.args.get('title') or ''
include_tag_inputs = request.args.getlist('include_tag') or '' include_tag_inputs = request.args.getlist('include_tag') or ''
exclude_tag_inputs = request.args.getlist('exclude_tag') or '' exclude_tag_inputs = request.args.getlist('exclude_tag') or ''
q = q.filter(db.Books.authors.any(func.lower(db.Authors.name).ilike("%" + author_input + "%")), q = q.filter(db.Books.authors.any(func.lower(db.Authors.name).ilike("%" + author_input + "%")),