From 8e5bb02a284adcdc3d7bab791c8526566e847b9c Mon Sep 17 00:00:00 2001 From: Ozzieisaacs Date: Sat, 13 Nov 2021 17:57:01 +0400 Subject: [PATCH] Merge author rename --- cps/db.py | 48 +++++++++++++++++++++++---------------- cps/editbooks.py | 8 +++---- cps/helper.py | 59 ++++++++++++++++++++++++++++++++---------------- cps/opds.py | 14 ++++++------ cps/ub.py | 2 ++ cps/web.py | 15 ++++++++---- 6 files changed, 90 insertions(+), 56 deletions(-) diff --git a/cps/db.py b/cps/db.py index f2acb7a1..06019e17 100644 --- a/cps/db.py +++ b/cps/db.py @@ -39,7 +39,6 @@ except ImportError: from sqlalchemy.pool import StaticPool from sqlalchemy.sql.expression import and_, true, false, text, func, or_ from sqlalchemy.ext.associationproxy import association_proxy -from sqlalchemy.orm import joinedload from flask_login import current_user from flask_babel import gettext as _ from flask import flash @@ -759,26 +758,32 @@ class CalibreDB(): entries = query.order_by(*order).offset(off).limit(pagesize).all() except Exception as ex: log.debug_or_exception(ex) + # display authors in right order + entries = self.order_authors(entries, True) return entries, randm, pagination # Orders all Authors in the list according to authors sort - def order_authors(self, entry): - sort_authors = entry.author_sort.split('&') - authors_ordered = list() - error = False - ids = [a.id for a in entry.authors] - for auth in sort_authors: - results = self.session.query(Authors).filter(Authors.sort == auth.lstrip().strip()).all() - # ToDo: How to handle not found authorname - if not len(results): - error = True - break - for r in results: - if r.id in ids: - authors_ordered.append(r) - if not error: - entry.authors = authors_ordered - return authors_ordered + def order_authors(self, entries, list_return=False): + for entry in entries: + sort_authors = entry.author_sort.split('&') + authors_ordered = list() + error = False + ids = [a.id for a in entry.authors] + for auth in sort_authors: + results = self.session.query(Authors).filter(Authors.sort == auth.lstrip().strip()).all() + # ToDo: How to handle not found authorname + if not len(results): + error = True + break + for r in results: + if r.id in ids: + authors_ordered.append(r) + if not error: + entry.authors = authors_ordered + if list_return: + return entries + else: + return authors_ordered def get_typeahead(self, database, query, replace=('', ''), tag_filter=true()): query = query or '' @@ -839,10 +844,10 @@ class CalibreDB(): )) # read search results from calibre-database and return it (function is used for feed and simple search - def get_search_results(self, term, offset=None, order=None, limit=None, *join): + def get_search_results(self, term, offset=None, order=None, limit=None, config_read_column=False, *join): order = order[0] if order else [Books.sort] pagination = None - result = self.search_query(term, *join).order_by(*order).all() + result = self.search_query(term, config_read_column, *join).order_by(*order).all() result_count = len(result) if offset != None and limit != None: offset = int(offset) @@ -853,6 +858,9 @@ class CalibreDB(): limit_all = result_count ub.store_combo_ids(result) + # ToDo: doesn't work as more than one table returned + # entries = self.order_authors(result[offset:limit_all], True) + return result[offset:limit_all], result_count, pagination # Creates for all stored languages a translated speaking name in the array for the UI diff --git a/cps/editbooks.py b/cps/editbooks.py index 9e5dd70d..bf971b15 100644 --- a/cps/editbooks.py +++ b/cps/editbooks.py @@ -171,7 +171,7 @@ def add_objects(db_book_object, db_object, db_session, db_type, add_elements): def create_objects_for_addition(db_element, add_element, db_type): if db_type == 'custom': if db_element.value != add_element: - db_element.value = add_element # ToDo: Before new_element, but this is not plausible + db_element.value = add_element elif db_type == 'languages': if db_element.lang_code != add_element: db_element.lang_code = add_element @@ -182,7 +182,7 @@ def create_objects_for_addition(db_element, add_element, db_type): elif db_type == 'author': if db_element.name != add_element: db_element.name = add_element - db_element.sort = add_element.replace('|', ',') + db_element.sort = helper.get_sorted_author(add_element.replace('|', ',')) elif db_type == 'publisher': if db_element.name != add_element: db_element.name = add_element @@ -376,7 +376,7 @@ def render_edit_book(book_id): for lang in book.languages: lang.language_name = isoLanguages.get_language_name(get_locale(), lang.lang_code) - book.authors = calibre_db.order_authors(book) + book.authors = calibre_db.order_authors([book]) author_names = [] for authr in book.authors: @@ -1286,7 +1286,7 @@ def table_xchange_author_title(): modif_date = False book = calibre_db.get_book(val) authors = book.title - book.authors = calibre_db.order_authors(book) + book.authors = calibre_db.order_authors([book]) author_names = [] for authr in book.authors: author_names.append(authr.name.replace('|', ',')) diff --git a/cps/helper.py b/cps/helper.py index 2cc7591b..9f7061c2 100644 --- a/cps/helper.py +++ b/cps/helper.py @@ -334,6 +334,32 @@ def delete_book_file(book, calibrepath, book_format=None): id=book.id, path=book.path) + +def clean_author_database(renamed_author, calibrepath, local_book=None): + valid_filename_authors = [get_valid_filename(r) for r in renamed_author] + for r in renamed_author: + if local_book: + all_books = [local_book] + else: + all_books = calibre_db.session.query(db.Books) \ + .filter(db.Books.authors.any(db.Authors.name == r)).all() + for book in all_books: + book_author_path = book.path.split('/')[0] + if book_author_path in valid_filename_authors or local_book: + new_author = calibre_db.session.query(db.Authors).filter(db.Authors.name == r).first() + all_new_authordir = get_valid_filename(new_author.name) + all_titledir = book.path.split('/')[1] + all_new_path = os.path.join(calibrepath, all_new_authordir, all_titledir) + all_new_name = get_valid_filename(book.title) + ' - ' + all_new_authordir + # change location in database to new author/title path + book.path = os.path.join(all_new_authordir, all_titledir).replace('\\', '/') + for file_format in book.data: + shutil.move(os.path.normcase( + os.path.join(all_new_path, file_format.name + '.' + file_format.format.lower())), + os.path.normcase(os.path.join(all_new_path, all_new_name + '.' + file_format.format.lower()))) + file_format.name = all_new_name + + # was muss gemacht werden: # Die Autorennamen müssen separiert werden und von dupletten bereinigt werden. # Es muss geprüft werden: @@ -366,13 +392,16 @@ def update_dir_structure_file(book_id, calibrepath, first_author, orignal_filepa if first_author: new_authordir = get_valid_filename(first_author) for r in renamed_author: - if first_author.lower() == r.lower(): + new_author = calibre_db.session.query(db.Authors).filter(db.Authors.name == r).first() + old_author_dir = get_valid_filename(r) + new_author_rename_dir = get_valid_filename(new_author.name) + if os.path.isdir(os.path.join(calibrepath, old_author_dir)): try: - new_author_path = os.path.join(calibrepath, new_authordir) - old_author_path = os.path.join(calibrepath, r) + old_author_path = os.path.join(calibrepath, old_author_dir) + new_author_path = os.path.join(calibrepath, new_author_rename_dir) shutil.move(os.path.normcase(old_author_path), os.path.normcase(new_author_path)) except (OSError) as ex: - log.error("Rename author from: %s to %s: %s", r, new_authordir, ex) + log.error("Rename author from: %s to %s: %s", old_author_path, new_author_path, ex) log.debug(ex, exc_info=True) return _("Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s", src=old_author_path, dest=new_author_path, error=str(ex)) @@ -411,26 +440,16 @@ def update_dir_structure_file(book_id, calibrepath, first_author, orignal_filepa # Rename all files from old names to new names try: - all_books = calibre_db.session.query(db.Books)\ - .filter(db.Books.authors.any(db.Authors.name == renamed_author)).all() - for book in all_books: - all_titledir = book.path.split('/')[1] - all_new_path = os.path.join(calibrepath, new_authordir, all_titledir) - all_new_name = get_valid_filename(book.title) + ' - ' + new_authordir - # change location in database to new author/title path - book.path = os.path.join(new_authordir, all_titledir).replace('\\', '/') - for file_format in book.data: - shutil.move(os.path.normcase( - os.path.join(all_new_path, file_format.name + '.' + file_format.format.lower())), - os.path.normcase(os.path.join(all_new_path, all_new_name + '.' + file_format.format.lower()))) - file_format.name = all_new_name + clean_author_database(renamed_author, calibrepath) + + if first_author not in renamed_author: + clean_author_database([first_author], calibrepath, localbook) if not renamed_author and not orignal_filepath and len(os.listdir(os.path.dirname(path))) == 0: shutil.rmtree(os.path.dirname(path)) except (OSError) as ex: - log.error("Rename file in path %s to %s: %s", all_new_path, all_new_name, ex) + log.error("Error in rename file in path %s", ex) log.debug(ex, exc_info=True) - return _("Rename file in path '%(src)s' to '%(dest)s' failed with error: %(error)s", - src=new_path, dest=new_name, error=str(ex)) + return _("Error in rename file in path: %(error)s", error=str(ex)) return False def update_dir_structure_gdrive(book_id, first_author): diff --git a/cps/opds.py b/cps/opds.py index 92c51d1b..f249218c 100644 --- a/cps/opds.py +++ b/cps/opds.py @@ -20,23 +20,21 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import sys import datetime +from urllib.parse import unquote_plus from functools import wraps from flask import Blueprint, request, render_template, Response, g, make_response, abort from flask_login import current_user from sqlalchemy.sql.expression import func, text, or_, and_, true from werkzeug.security import check_password_hash - +from tornado.httputil import HTTPServerRequest from . import constants, logger, config, db, calibre_db, ub, services, get_locale, isoLanguages from .helper import get_download_link, get_book_cover from .pagination import Pagination from .web import render_read_books from .usermanagement import load_user_from_request from flask_babel import gettext as _ -from babel import Locale as LC -from babel.core import UnknownLocaleError opds = Blueprint('opds', __name__) @@ -84,10 +82,12 @@ def feed_osd(): @opds.route("/opds/search", defaults={'query': ""}) -@opds.route("/opds/search/") +@opds.route("/opds/search/") @requires_basic_auth_if_no_ano def feed_cc_search(query): - return feed_search(query.strip()) + # Handle strange query from Libera Reader with + instead of spaces + plus_query = unquote_plus(request.base_url.split('/opds/search/')[1]).strip() + return feed_search(plus_query) @opds.route("/opds/search", methods=["GET"]) @@ -527,7 +527,7 @@ def get_metadata_calibre_companion(uuid, library): def feed_search(term): if term: - entries, __, ___ = calibre_db.get_search_results(term) + entries, __, ___ = calibre_db.get_search_results(term, config_read_column=config.config_read_column) entriescount = len(entries) if len(entries) > 0 else 1 pagination = Pagination(1, entriescount, entriescount) return render_xml_template('feed.xml', searchterm=term, entries=entries, pagination=pagination) diff --git a/cps/ub.py b/cps/ub.py index e9ad264f..6530a595 100644 --- a/cps/ub.py +++ b/cps/ub.py @@ -83,6 +83,8 @@ def signal_store_user_session(object, user): store_user_session() def store_user_session(): + if flask_session.get('user_id', ""): + flask_session['_user_id'] = flask_session.get('user_id', "") if flask_session.get('_user_id', ""): try: if not check_user_session(flask_session.get('_user_id', ""), flask_session.get('_id', "")): diff --git a/cps/web.py b/cps/web.py index 9809c4e0..6d1b9866 100644 --- a/cps/web.py +++ b/cps/web.py @@ -543,7 +543,6 @@ def render_author_books(page, author_id, order): if services.goodreads_support and config.config_use_goodreads: author_info = services.goodreads_support.get_author_info(author_name) other_books = services.goodreads_support.get_other_books(author_info, entries) - return render_title_template('author.html', entries=entries, pagination=pagination, id=author_id, title=_(u"Author: %(name)s", name=author_name), author=author_info, other_books=other_books, page="author", order=order[1]) @@ -753,7 +752,12 @@ def render_prepare_search_form(cc): def render_search_results(term, offset=None, order=None, limit=None): join = db.books_series_link, db.Books.id == db.books_series_link.c.book, db.Series - entries, result_count, pagination = calibre_db.get_search_results(term, offset, order, limit, *join) + entries, result_count, pagination = calibre_db.get_search_results(term, + offset, + order, + limit, + config.config_read_column, + *join) return render_title_template('search.html', searchterm=term, pagination=pagination, @@ -832,7 +836,7 @@ def list_books(): total_count = filtered_count = calibre_db.session.query(db.Books).filter(calibre_db.common_filters(False)).count() if state is not None: if search: - books = calibre_db.search_query(search).all() + books = calibre_db.search_query(search, config.config_read_column).all() filtered_count = len(books) else: if not config.config_read_column: @@ -1424,10 +1428,11 @@ def render_adv_search_results(term, offset=None, order=None, limit=None): else: offset = 0 limit_all = result_count + entries = calibre_db.order_authors(q[offset:limit_all], True) return render_title_template('search.html', adv_searchterm=searchterm, pagination=pagination, - entries=q[offset:limit_all], + entries=entries, result_count=result_count, title=_(u"Advanced Search"), page="advsearch", order=order[1]) @@ -1830,7 +1835,7 @@ def show_book(book_id): entry.tags = sort(entry.tags, key=lambda tag: tag.name) - entry.authors = calibre_db.order_authors(entry) + entry.authors = calibre_db.order_authors([entry]) entry.kindle_list = check_send_to_kindle(entry) entry.reader_list = check_read_formats(entry)