From c1d0ec076ba9d1a2a7c56fe5cfdd25c4472e79b2 Mon Sep 17 00:00:00 2001 From: flying-sausages Date: Wed, 26 May 2021 17:20:54 +0200 Subject: [PATCH 1/4] Shield cleanup --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 177afe43..e1198f8f 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,12 @@ Calibre-Web is a web app providing a clean interface for browsing, reading and downloading eBooks using an existing [Calibre](https://calibre-ebook.com) database. -![GitHub License](https://img.shields.io/github/license/janeczku/calibre-web) ![GitHub Downloads](https://img.shields.io/github/downloads/janeczku/calibre-web/total) ![GitHub commit activity](https://img.shields.io/github/commit-activity/w/janeczku/calibre-web?logo=github) [![Discord](https://img.shields.io/discord/838810113564344381?label=Discord&logo=discord)](https://discord.gg/h2VsJ2NEfB) +[![GitHub License](https://img.shields.io/github/license/janeczku/calibre-web?style=flat-square)](https://github.com/janeczku/calibre-web/blob/master/LICENSE) +[![GitHub commit activity](https://img.shields.io/github/commit-activity/w/janeczku/calibre-web?logo=github&style=flat-square&label=commits)]() +[![GitHub all releases](https://img.shields.io/github/downloads/janeczku/calibre-web/total?logo=github&style=flat-square)](https://github.com/janeczku/calibre-web/releases) +[![PyPI](https://img.shields.io/pypi/v/calibreweb?logo=pypi&logoColor=fff&style=flat-square)](https://pypi.org/project/calibreweb/) +[![PyPI - Downloads](https://img.shields.io/pypi/dm/calibreweb?logo=pypi&logoColor=fff&style=flat-square)](https://pypi.org/project/calibreweb/) +[![Discord](https://img.shields.io/discord/838810113564344381?label=Discord&logo=discord&style=flat-square)](https://discord.gg/h2VsJ2NEfB) *This software is a fork of [library](https://github.com/mutschler/calibreserver) and licensed under the GPL v3 License.* From 25add6511f7deb739b16a88ba2f907abdc33dc2e Mon Sep 17 00:00:00 2001 From: Ozzie Isaacs Date: Fri, 28 May 2021 14:54:18 +0200 Subject: [PATCH 2/4] Catch error on search for new custom column (created after start of calibre-web) --- cps/web.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cps/web.py b/cps/web.py index 0dafb505..998d1779 100644 --- a/cps/web.py +++ b/cps/web.py @@ -1327,7 +1327,11 @@ def render_adv_search_results(term, offset=None, order=None, limit=None): q = q.filter(db.Books.comments.any(func.lower(db.Comments.text).ilike("%" + description + "%"))) # search custom culumns - q = adv_search_custom_columns(cc, term, q) + try: + q = adv_search_custom_columns(cc, term, q) + except AttributeError as ex: + log.debug_or_exception(ex) + flash(_("Error on search for custom columns, please restart Calibre-Web"), category="error") q = q.order_by(*order).all() flask_session['query'] = json.dumps(term) From 62fce266516c5fcf36547e30fbd3db4c56b535bf Mon Sep 17 00:00:00 2001 From: Ozzie Isaacs Date: Fri, 28 May 2021 14:57:35 +0200 Subject: [PATCH 3/4] Bugfix extended search term with excluded series/shelfs --- cps/web.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cps/web.py b/cps/web.py index 998d1779..ba3c5ae3 100644 --- a/cps/web.py +++ b/cps/web.py @@ -1211,7 +1211,7 @@ def extend_search_term(searchterm, for key, db_element in elements.items(): tag_names = calibre_db.session.query(db_element).filter(db_element.id.in_(tags['include_' + key])).all() searchterm.extend(tag.name for tag in tag_names) - tag_names = calibre_db.session.query(db_element).filter(db.Tags.id.in_(tags['exclude_' + key])).all() + tag_names = calibre_db.session.query(db_element).filter(db_element.id.in_(tags['exclude_' + key])).all() searchterm.extend(tag.name for tag in tag_names) language_names = calibre_db.session.query(db.Languages). \ filter(db.Languages.id.in_(tags['include_language'])).all() From a79600c81f384cf7f61b0300fd73e459720e748d Mon Sep 17 00:00:00 2001 From: Ozzie Isaacs Date: Fri, 28 May 2021 18:22:29 +0200 Subject: [PATCH 4/4] Mass change book title and author (fix #1996) --- cps/editbooks.py | 52 ++++++++++++++++++++++++++++++++--- cps/static/js/table.js | 19 +++++++++++++ cps/templates/book_table.html | 11 +++++--- 3 files changed, 74 insertions(+), 8 deletions(-) diff --git a/cps/editbooks.py b/cps/editbooks.py index b5791c54..dd8bf420 100644 --- a/cps/editbooks.py +++ b/cps/editbooks.py @@ -1148,11 +1148,15 @@ def edit_list_book(param): 'newValue': ' & '.join([author.replace('|',',') for author in input_authors])}), mimetype='application/json') book.last_modified = datetime.utcnow() - calibre_db.session.commit() - # revert change for sort if automatic fields link is deactivated - if param == 'title' and vals.get('checkT') == "false": - book.sort = sort + try: calibre_db.session.commit() + # revert change for sort if automatic fields link is deactivated + if param == 'title' and vals.get('checkT') == "false": + book.sort = sort + calibre_db.session.commit() + except (OperationalError, IntegrityError) as e: + calibre_db.session.rollback() + log.error("Database error: %s", e) return ret @@ -1224,3 +1228,43 @@ def merge_list_book(): delete_book(from_book.id,"", True) return json.dumps({'success': True}) return "" + +@editbook.route("/ajax/xchange", methods=['POST']) +@login_required +@edit_required +def table_xchange_author_title(): + vals = request.get_json().get('xchange') + if vals: + for val in vals: + modif_date = False + book = calibre_db.get_book(val) + authors = book.title + entries = calibre_db.order_authors(book) + author_names = [] + for authr in entries.authors: + author_names.append(authr.name.replace('|', ',')) + + title_change = handle_title_on_edit(book, " ".join(author_names)) + input_authors, authorchange = handle_author_on_edit(book, authors) + if authorchange or title_change: + edited_books_id = book.id + modif_date = True + + if config.config_use_google_drive: + gdriveutils.updateGdriveCalibreFromLocal() + + if edited_books_id: + helper.update_dir_stucture(edited_books_id, config.config_calibre_dir, input_authors[0]) + if modif_date: + book.last_modified = datetime.utcnow() + try: + calibre_db.session.commit() + except (OperationalError, IntegrityError) as e: + calibre_db.session.rollback() + log.error("Database error: %s", e) + return json.dumps({'success': False}) + + if config.config_use_google_drive: + gdriveutils.updateGdriveCalibreFromLocal() + return json.dumps({'success': True}) + return "" diff --git a/cps/static/js/table.js b/cps/static/js/table.js index 88694837..a38ca1c6 100644 --- a/cps/static/js/table.js +++ b/cps/static/js/table.js @@ -46,9 +46,14 @@ $(function() { if (selections.length < 1) { $("#delete_selection").addClass("disabled"); $("#delete_selection").attr("aria-disabled", true); + $("#table_xchange").addClass("disabled"); + $("#table_xchange").attr("aria-disabled", true); } else { $("#delete_selection").removeClass("disabled"); $("#delete_selection").attr("aria-disabled", false); + $("#table_xchange").removeClass("disabled"); + $("#table_xchange").attr("aria-disabled", false); + } }); $("#delete_selection").click(function() { @@ -86,6 +91,20 @@ $(function() { }); }); + $("#table_xchange").click(function() { + $.ajax({ + method:"post", + contentType: "application/json; charset=utf-8", + dataType: "json", + url: window.location.pathname + "/../../ajax/xchange", + data: JSON.stringify({"xchange":selections}), + success: function success() { + $("#books-table").bootstrapTable("refresh"); + $("#books-table").bootstrapTable("uncheckAll"); + } + }); + }); + var column = []; $("#books-table > thead > tr > th").each(function() { var element = {}; diff --git a/cps/templates/book_table.html b/cps/templates/book_table.html index d088e54b..e340dc0a 100644 --- a/cps/templates/book_table.html +++ b/cps/templates/book_table.html @@ -20,17 +20,20 @@ {% block body %}

{{_(title)}}

-
+
{{_('Merge selected books')}}
{{_('Remove Selections')}}
+
+
{{_('Exchange author and title')}}
+
-
-
+
+
-
+