diff --git a/cps/helper.py b/cps/helper.py index 63f77950..63e6dc9d 100644 --- a/cps/helper.py +++ b/cps/helper.py @@ -19,7 +19,7 @@ # along with this program. If not, see . -from cps import config, global_WorkerThread, get_locale, db +from cps import config, global_WorkerThread, get_locale, db, mimetypes from flask import current_app as app from tempfile import gettempdir import sys @@ -40,6 +40,7 @@ import requests from sqlalchemy.sql.expression import true, and_, false, text, func from iso639 import languages as isoLanguages from pagination import Pagination +from werkzeug.datastructures import Headers try: import gdriveutils as gd @@ -49,12 +50,23 @@ import random from subproc_wrapper import process_open import ub +try: + from urllib.parse import quote +except ImportError: + from urllib import quote + try: import unidecode use_unidecode = True except ImportError: use_unidecode = False +try: + import Levenshtein + use_levenshtein = True +except ImportError: + use_levenshtein = False + def update_download(book_id, user_id): check = ub.session.query(ub.Downloads).filter(ub.Downloads.user_id == user_id).filter(ub.Downloads.book_id == @@ -660,7 +672,7 @@ def get_unique_other_books(library_books, author_books): author_books) # Fuzzy match book titles - if feature_support['levenshtein']: + if use_levenshtein: library_titles = reduce(lambda acc, book: acc + [book.title], library_books, []) other_books = filter(lambda author_book: not filter( lambda library_book: @@ -670,3 +682,40 @@ def get_unique_other_books(library_books, author_books): ), other_books) return other_books + + +def get_cc_columns(): + tmpcc = db.session.query(db.Custom_Columns).filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all() + if config.config_columns_to_ignore: + cc = [] + for col in tmpcc: + r = re.compile(config.config_columns_to_ignore) + if r.match(col.label): + cc.append(col) + else: + cc = tmpcc + return cc + +def get_download_link(book_id, book_format): + book_format = book_format.split(".")[0] + book = db.session.query(db.Books).filter(db.Books.id == book_id).first() + data = db.session.query(db.Data).filter(db.Data.book == book.id)\ + .filter(db.Data.format == book_format.upper()).first() + if data: + # collect downloaded books only for registered user and not for anonymous user + if current_user.is_authenticated: + ub.update_download(book_id, int(current_user.id)) + file_name = book.title + if len(book.authors) > 0: + file_name = book.authors[0].name + '_' + file_name + file_name = get_valid_filename(file_name) + headers = Headers() + try: + headers["Content-Type"] = mimetypes.types_map['.' + book_format] + except KeyError: + headers["Content-Type"] = "application/octet-stream" + headers["Content-Disposition"] = "attachment; filename*=UTF-8''%s.%s" % (quote(file_name.encode('utf-8')), + book_format) + return do_download_file(book, book_format, data, headers) + else: + abort(404) diff --git a/cps/opds.py b/cps/opds.py index 873f7440..67bce0a1 100644 --- a/cps/opds.py +++ b/cps/opds.py @@ -22,7 +22,7 @@ # along with this program. If not, see . # opds routing functions -from cps import config, mimetypes, app, db +from cps import config, db from flask import request, render_template, Response, g, make_response from pagination import Pagination from flask import Blueprint @@ -34,7 +34,6 @@ from web import login_required_if_no_ano, common_filters, get_search_results, re from sqlalchemy.sql.expression import func, text import helper from werkzeug.security import check_password_hash -from werkzeug.datastructures import Headers from helper import fill_indexpage import sys @@ -58,7 +57,7 @@ def requires_basic_auth_if_no_ano(f): return decorated -@opds.route("/opds") +@opds.route("/opds/") @requires_basic_auth_if_no_ano def feed_index(): return render_xml_template('index.xml') @@ -258,25 +257,9 @@ def feed_shelf(book_id): @opds.route("/opds/download///") @requires_basic_auth_if_no_ano @download_required -def get_opds_download_link(book_id, book_format): - book_format = book_format.split(".")[0] - book = db.session.query(db.Books).filter(db.Books.id == book_id).first() - data = db.session.query(db.Data).filter(db.Data.book == book.id).filter(db.Data.format == book_format.upper()).first() - app.logger.info(data.name) - if current_user.is_authenticated: - ub.update_download(book_id, int(current_user.id)) - file_name = book.title - if len(book.authors) > 0: - file_name = book.authors[0].name + '_' + file_name - file_name = helper.get_valid_filename(file_name) - headers = Headers() - headers["Content-Disposition"] = "attachment; filename*=UTF-8''%s.%s" % (quote(file_name.encode('utf8')), - book_format) - try: - headers["Content-Type"] = mimetypes.types_map['.' + book_format] - except KeyError: - headers["Content-Type"] = "application/octet-stream" - return helper.do_download_file(book, book_format, data, headers) +def opds_download_link(book_id, book_format): + return helper.get_download_link(book_id,book_format) + @opds.route("/ajax/book/") @requires_basic_auth_if_no_ano diff --git a/cps/templates/detail.html b/cps/templates/detail.html index fb04fbf6..6cd61379 100644 --- a/cps/templates/detail.html +++ b/cps/templates/detail.html @@ -22,7 +22,7 @@ {{_('Download')}} : {% for format in entry.data %} - + {{format.format}} ({{ format.uncompressed_size|filesizeformat }}) {% endfor %} @@ -33,7 +33,7 @@ {% endif %} diff --git a/cps/templates/feed.xml b/cps/templates/feed.xml index f848720c..e007f71f 100644 --- a/cps/templates/feed.xml +++ b/cps/templates/feed.xml @@ -65,7 +65,7 @@ {% endif %} {% for format in entry.data %} - {% endfor %} diff --git a/cps/templates/json.txt b/cps/templates/json.txt index c068b1b4..5f8dffca 100644 --- a/cps/templates/json.txt +++ b/cps/templates/json.txt @@ -36,7 +36,7 @@ "timestamp": "{{entry.timestamp}}", "thumbnail": "{{url_for('opds.feed_get_cover', book_id=entry.id)}}", "main_format": { - "{{entry.data[0].format|lower}}": "{{ url_for('opds.get_opds_download_link', book_id=entry.id, book_format=entry.data[0].format|lower)}}" + "{{entry.data[0].format|lower}}": "{{ url_for('web.download_link', book_id=entry.id, book_format=entry.data[0].format|lower)}}" }, "rating":{% if entry.ratings.__len__() > 0 %} "{{entry.ratings[0].rating}}.0"{% else %}0.0{% endif %}, "authors": [ @@ -47,7 +47,7 @@ "other_formats": { {% if entry.data.__len__() > 1 %} {% for format in entry.data[1:] %} - "{{format.format|lower}}": "{{ url_for('opds.get_opds_download_link', book_id=entry.id, book_format=format.format|lower)}}"{% if not loop.last %},{% endif %} + "{{format.format|lower}}": "{{ url_for('web.download_link', book_id=entry.id, book_format=format.format|lower)}}"{% if not loop.last %},{% endif %} {% endfor %} {% endif %} }, "title_sort": "{{entry.sort}}" diff --git a/cps/templates/read.html b/cps/templates/read.html index 3ef624e0..7f5e9ac9 100644 --- a/cps/templates/read.html +++ b/cps/templates/read.html @@ -84,7 +84,7 @@ filePath: "{{ url_for('static', filename='js/libs/') }}", cssPath: "{{ url_for('static', filename='css/') }}", bookmarkUrl: "{{ url_for('web.bookmark', book_id=bookid, book_format='EPUB') }}", - bookUrl: "{{ url_for('web.get_download_link_ext', book_id=bookid, book_format='epub', anyname='file.epub') }}", + bookUrl: "{{ url_for('web.download_link', book_id=bookid, book_format='epub', anyname='file.epub') }}", bookmark: "{{ bookmark.bookmark_key if bookmark != None }}", useBookmarks: "{{ g.user.is_authenticated | tojson }}" }; diff --git a/cps/templates/shelfdown.html b/cps/templates/shelfdown.html index 119330a7..53c845e0 100644 --- a/cps/templates/shelfdown.html +++ b/cps/templates/shelfdown.html @@ -53,7 +53,7 @@ {% if entry.data|length < 2 %} {% for format in entry.data %} - + {{format.format}} ({{ format.uncompressed_size|filesizeformat }}) {% endfor %} @@ -64,7 +64,7 @@ {% endif %} diff --git a/cps/web.py b/cps/web.py index a4d328d2..b0b7d087 100644 --- a/cps/web.py +++ b/cps/web.py @@ -37,7 +37,7 @@ from babel import Locale as LC from babel.dates import format_date from babel.core import UnknownLocaleError import base64 -from sqlalchemy.sql.expression import text, func, true, and_, false, not_ +from sqlalchemy.sql.expression import text, func, true, false, not_ import json import datetime from iso639 import languages as isoLanguages @@ -63,7 +63,7 @@ except ImportError: feature_support['ldap'] = False try: - from googleapiclient.errors import HttpError + from googleapiclient.errors import HttpErrort except ImportError: pass @@ -73,12 +73,6 @@ try: except ImportError: feature_support['goodreads'] = False -try: - import Levenshtein - feature_support['levenshtein'] = True -except ImportError: - feature_support['levenshtein'] = False - try: from functools import reduce, wraps except ImportError: @@ -110,7 +104,7 @@ EXTENSIONS_UPLOAD = {'txt', 'pdf', 'epub', 'mobi', 'azw', 'azw3', 'cbr', 'cbz', 'fb2', 'html', 'rtf', 'odt', 'mp3', 'm4a', 'm4b'} -'''EXTENSIONS_READER = set(['txt', 'pdf', 'epub', 'zip', 'cbz', 'tar', 'cbt'] + +'''EXTENSIONS_READER = set(['txt', 'pdf', 'epub', 'zip', 'cbz', 'tar', 'cbt'] + (['rar','cbr'] if feature_support['rar'] else []))''' @@ -848,7 +842,8 @@ def search(): @login_required_if_no_ano def advanced_search(): # Build custom columns names - tmpcc = db.session.query(db.Custom_Columns).filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all() + cc = helper.get_cc_columns() + '''tmpcc = db.session.query(db.Custom_Columns).filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all() if config.config_columns_to_ignore: cc = [] for col in tmpcc: @@ -856,7 +851,7 @@ def advanced_search(): if r.match(col.label): cc.append(col) else: - cc = tmpcc + cc = tmpcc''' db.session.connection().connection.connection.create_function("lower", 1, db.lcase) q = db.session.query(db.Books) @@ -1074,39 +1069,12 @@ def serve_book(book_id, book_format): return send_from_directory(os.path.join(config.config_calibre_dir, book.path), data.name + "." + book_format) -@web.route("/download//") -@login_required_if_no_ano -@download_required -def get_download_link(book_id, book_format): - book_format = book_format.split(".")[0] - book = db.session.query(db.Books).filter(db.Books.id == book_id).first() - data = db.session.query(db.Data).filter(db.Data.book == book.id)\ - .filter(db.Data.format == book_format.upper()).first() - if data: - # collect downloaded books only for registered user and not for anonymous user - if current_user.is_authenticated: - ub.update_download(book_id, int(current_user.id)) - file_name = book.title - if len(book.authors) > 0: - file_name = book.authors[0].name + '_' + file_name - file_name = helper.get_valid_filename(file_name) - headers = Headers() - try: - headers["Content-Type"] = mimetypes.types_map['.' + book_format] - except KeyError: - headers["Content-Type"] = "application/octet-stream" - headers["Content-Disposition"] = "attachment; filename*=UTF-8''%s.%s" % (quote(file_name.encode('utf-8')), - book_format) - return helper.do_download_file(book, book_format, data, headers) - else: - abort(404) - - +@web.route("/download//", defaults={'anyname': 'None'}) @web.route("/download///") @login_required_if_no_ano @download_required -def get_download_link_ext(book_id, book_format, anyname): - return get_download_link(book_id, book_format) +def download_link(book_id, book_format, anyname): + return helper.get_download_link(book_id, book_format) @web.route('/send///') @@ -1457,7 +1425,8 @@ def show_book(book_id): except UnknownLocaleError: entries.languages[index].language_name = _( isoLanguages.get(part3=entries.languages[index].lang_code).name) - tmpcc = db.session.query(db.Custom_Columns).filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all() + cc = helper.get_cc_columns() + '''tmpcc = db.session.query(db.Custom_Columns).filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all() if config.config_columns_to_ignore: cc = [] @@ -1466,7 +1435,7 @@ def show_book(book_id): if r.match(col.label): cc.append(col) else: - cc = tmpcc + cc = tmpcc''' book_in_shelfs = [] shelfs = ub.session.query(ub.BookShelf).filter(ub.BookShelf.book_id == book_id).all() for entry in shelfs: