mirror of
				https://github.com/janeczku/calibre-web
				synced 2025-10-30 23:03:02 +00:00 
			
		
		
		
	Merge branch 'master' into Develop
This commit is contained in:
		| @@ -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. | 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. | ||||||
|  |  | ||||||
|    [](https://discord.gg/h2VsJ2NEfB)  | [](https://github.com/janeczku/calibre-web/blob/master/LICENSE) | ||||||
|  | []() | ||||||
|  | [](https://github.com/janeczku/calibre-web/releases) | ||||||
|  | [](https://pypi.org/project/calibreweb/) | ||||||
|  | [](https://pypi.org/project/calibreweb/) | ||||||
|  | [](https://discord.gg/h2VsJ2NEfB) | ||||||
|  |  | ||||||
| *This software is a fork of [library](https://github.com/mutschler/calibreserver) and licensed under the GPL v3 License.* | *This software is a fork of [library](https://github.com/mutschler/calibreserver) and licensed under the GPL v3 License.* | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1148,11 +1148,15 @@ def edit_list_book(param): | |||||||
|                                    'newValue':  ' & '.join([author.replace('|',',') for author in input_authors])}), |                                    'newValue':  ' & '.join([author.replace('|',',') for author in input_authors])}), | ||||||
|                        mimetype='application/json') |                        mimetype='application/json') | ||||||
|     book.last_modified = datetime.utcnow() |     book.last_modified = datetime.utcnow() | ||||||
|  |     try: | ||||||
|         calibre_db.session.commit() |         calibre_db.session.commit() | ||||||
|         # revert change for sort if automatic fields link is deactivated |         # revert change for sort if automatic fields link is deactivated | ||||||
|         if param == 'title' and vals.get('checkT') == "false": |         if param == 'title' and vals.get('checkT') == "false": | ||||||
|             book.sort = sort |             book.sort = sort | ||||||
|             calibre_db.session.commit() |             calibre_db.session.commit() | ||||||
|  |     except (OperationalError, IntegrityError) as e: | ||||||
|  |         calibre_db.session.rollback() | ||||||
|  |         log.error("Database error: %s", e) | ||||||
|     return ret |     return ret | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -1224,3 +1228,43 @@ def merge_list_book(): | |||||||
|                     delete_book(from_book.id,"", True) |                     delete_book(from_book.id,"", True) | ||||||
|                     return json.dumps({'success': True}) |                     return json.dumps({'success': True}) | ||||||
|     return "" |     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 "" | ||||||
|   | |||||||
| @@ -46,9 +46,14 @@ $(function() { | |||||||
|             if (selections.length < 1) { |             if (selections.length < 1) { | ||||||
|                 $("#delete_selection").addClass("disabled"); |                 $("#delete_selection").addClass("disabled"); | ||||||
|                 $("#delete_selection").attr("aria-disabled", true); |                 $("#delete_selection").attr("aria-disabled", true); | ||||||
|  |                 $("#table_xchange").addClass("disabled"); | ||||||
|  |                 $("#table_xchange").attr("aria-disabled", true); | ||||||
|             } else { |             } else { | ||||||
|                 $("#delete_selection").removeClass("disabled"); |                 $("#delete_selection").removeClass("disabled"); | ||||||
|                 $("#delete_selection").attr("aria-disabled", false); |                 $("#delete_selection").attr("aria-disabled", false); | ||||||
|  |                 $("#table_xchange").removeClass("disabled"); | ||||||
|  |                 $("#table_xchange").attr("aria-disabled", false); | ||||||
|  |  | ||||||
|             } |             } | ||||||
|         }); |         }); | ||||||
|     $("#delete_selection").click(function() { |     $("#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 = []; |     var column = []; | ||||||
|     $("#books-table > thead > tr > th").each(function() { |     $("#books-table > thead > tr > th").each(function() { | ||||||
|         var element = {}; |         var element = {}; | ||||||
|   | |||||||
| @@ -20,17 +20,20 @@ | |||||||
| {% block body %} | {% block body %} | ||||||
| <h2 class="{{page}}">{{_(title)}}</h2> | <h2 class="{{page}}">{{_(title)}}</h2> | ||||||
|       <div class="col-xs-12 col-sm-6"> |       <div class="col-xs-12 col-sm-6"> | ||||||
|         <div class="row"> |         <div class="row form-group"> | ||||||
|           <div class="btn btn-default disabled" id="merge_books" data-toggle="modal" data-target="#mergeModal" aria-disabled="true">{{_('Merge selected books')}}</div> |           <div class="btn btn-default disabled" id="merge_books" data-toggle="modal" data-target="#mergeModal" aria-disabled="true">{{_('Merge selected books')}}</div> | ||||||
|           <div class="btn btn-default disabled" id="delete_selection" aria-disabled="true">{{_('Remove Selections')}}</div> |           <div class="btn btn-default disabled" id="delete_selection" aria-disabled="true">{{_('Remove Selections')}}</div> | ||||||
|         </div> |         </div> | ||||||
|  |         <div class="row form-group"> | ||||||
|  |             <div class="btn btn-default disabled" id="table_xchange" ><span class="glyphicon glyphicon-arrow-up"></span><span class="glyphicon glyphicon-arrow-down"></span>{{_('Exchange author and title')}}</div> | ||||||
|         </div> |         </div> | ||||||
|      <div class="col-xs-12 col-sm-6"> |       </div> | ||||||
|       <div class="row"> |      <div class="filterheader col-xs-12 col-sm-6"> | ||||||
|  |       <div class="row form-group"> | ||||||
|         <input type="checkbox" id="autoupdate_titlesort" name="autoupdate_titlesort" checked> |         <input type="checkbox" id="autoupdate_titlesort" name="autoupdate_titlesort" checked> | ||||||
|         <label for="autoupdate_titlesort">{{_('Update Title Sort automatically')}}</label> |         <label for="autoupdate_titlesort">{{_('Update Title Sort automatically')}}</label> | ||||||
|       </div> |       </div> | ||||||
|       <div class="row"> |       <div class="row form-group"> | ||||||
|         <input type="checkbox" id="autoupdate_authorsort" name="autoupdate_authorsort" checked> |         <input type="checkbox" id="autoupdate_authorsort" name="autoupdate_authorsort" checked> | ||||||
|         <label for="autoupdate_authorsort">{{_('Update Author Sort automatically')}}</label> |         <label for="autoupdate_authorsort">{{_('Update Author Sort automatically')}}</label> | ||||||
|       </div> |       </div> | ||||||
|   | |||||||
| @@ -1211,7 +1211,7 @@ def extend_search_term(searchterm, | |||||||
|     for key, db_element in elements.items(): |     for key, db_element in elements.items(): | ||||||
|         tag_names = calibre_db.session.query(db_element).filter(db_element.id.in_(tags['include_' + key])).all() |         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) |         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) |         searchterm.extend(tag.name for tag in tag_names) | ||||||
|     language_names = calibre_db.session.query(db.Languages). \ |     language_names = calibre_db.session.query(db.Languages). \ | ||||||
|         filter(db.Languages.id.in_(tags['include_language'])).all() |         filter(db.Languages.id.in_(tags['include_language'])).all() | ||||||
| @@ -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 + "%"))) |             q = q.filter(db.Books.comments.any(func.lower(db.Comments.text).ilike("%" + description + "%"))) | ||||||
|  |  | ||||||
|         # search custom culumns |         # search custom culumns | ||||||
|  |         try: | ||||||
|             q = adv_search_custom_columns(cc, term, q) |             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() |     q = q.order_by(*order).all() | ||||||
|     flask_session['query'] = json.dumps(term) |     flask_session['query'] = json.dumps(term) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Ozzie Isaacs
					Ozzie Isaacs