mirror of
https://github.com/janeczku/calibre-web
synced 2024-12-29 03:20:30 +00:00
Refactored generating download links
This commit is contained in:
parent
9c1b3f136f
commit
baf83b2f5a
@ -19,7 +19,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
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)
|
||||
|
27
cps/opds.py
27
cps/opds.py
@ -22,7 +22,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# 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/<book_id>/<book_format>/")
|
||||
@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/<string:uuid>")
|
||||
@requires_basic_auth_if_no_ano
|
||||
|
@ -22,7 +22,7 @@
|
||||
{{_('Download')}} :
|
||||
</button>
|
||||
{% for format in entry.data %}
|
||||
<a href="{{ url_for('web.get_download_link_ext', book_id=entry.id, book_format=format.format|lower, anyname=entry.id|string+'.'+format.format|lower) }}" id="btnGroupDrop1{{format.format|lower}}" class="btn btn-primary" role="button">
|
||||
<a href="{{ url_for('web.download_link', book_id=entry.id, book_format=format.format|lower, anyname=entry.id|string+'.'+format.format|lower) }}" id="btnGroupDrop1{{format.format|lower}}" class="btn btn-primary" role="button">
|
||||
<span class="glyphicon glyphicon-download"></span>{{format.format}} ({{ format.uncompressed_size|filesizeformat }})
|
||||
</a>
|
||||
{% endfor %}
|
||||
@ -33,7 +33,7 @@
|
||||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="btnGroupDrop1">
|
||||
{% for format in entry.data %}
|
||||
<li><a href="{{ url_for('web.get_download_link_ext', book_id=entry.id, book_format=format.format|lower, anyname=entry.id|string+'.'+format.format|lower) }}">{{format.format}} ({{ format.uncompressed_size|filesizeformat }})</a></li>
|
||||
<li><a href="{{ url_for('web.download_link', book_id=entry.id, book_format=format.format|lower, anyname=entry.id|string+'.'+format.format|lower) }}">{{format.format}} ({{ format.uncompressed_size|filesizeformat }})</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
@ -65,7 +65,7 @@
|
||||
<link type="image/jpeg" href="{{url_for('opds.feed_get_cover', book_id=entry.id)}}" rel="http://opds-spec.org/image/thumbnail"/>
|
||||
{% endif %}
|
||||
{% for format in entry.data %}
|
||||
<link rel="http://opds-spec.org/acquisition" href="{{ url_for('opds.get_opds_download_link', book_id=entry.id, book_format=format.format|lower)}}"
|
||||
<link rel="http://opds-spec.org/acquisition" href="{{ url_for('web.download_link', book_id=entry.id, book_format=format.format|lower)}}"
|
||||
length="{{format.uncompressed_size}}" mtime="{{entry.atom_timestamp}}" type="{{format.format|lower|mimetype}}"/>
|
||||
{% endfor %}
|
||||
</entry>
|
||||
|
@ -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}}"
|
||||
|
@ -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 }}"
|
||||
};
|
||||
|
@ -53,7 +53,7 @@
|
||||
{% if entry.data|length < 2 %}
|
||||
|
||||
{% for format in entry.data %}
|
||||
<a href="{{ url_for('web.get_download_link_ext', book_id=entry.id, book_format=format.format|lower, anyname=entry.id|string+'.'+format.format|lower) }}" id="btnGroupDrop1{{format.format|lower}}" class="btn btn-primary" role="button">
|
||||
<a href="{{ url_for('web.download_link', book_id=entry.id, book_format=format.format|lower, anyname=entry.id|string+'.'+format.format|lower) }}" id="btnGroupDrop1{{format.format|lower}}" class="btn btn-primary" role="button">
|
||||
<span class="glyphicon glyphicon-download"></span>{{format.format}} ({{ format.uncompressed_size|filesizeformat }})
|
||||
</a>
|
||||
{% endfor %}
|
||||
@ -64,7 +64,7 @@
|
||||
</button>
|
||||
<ul class="dropdown-menu" aria-labelledby="btnGroupDrop1">
|
||||
{% for format in entry.data %}
|
||||
<li><a href="{{ url_for('get_download_link_ext', book_id=entry.id, book_format=format.format|lower, anyname=entry.id|string+'.'+format.format|lower) }}">{{format.format}} ({{ format.uncompressed_size|filesizeformat }})</a></li>
|
||||
<li><a href="{{ url_for('web.download_link', book_id=entry.id, book_format=format.format|lower, anyname=entry.id|string+'.'+format.format|lower) }}">{{format.format}} ({{ format.uncompressed_size|filesizeformat }})</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
55
cps/web.py
55
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/<int:book_id>/<book_format>")
|
||||
@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/<int:book_id>/<book_format>", defaults={'anyname': 'None'})
|
||||
@web.route("/download/<int:book_id>/<book_format>/<anyname>")
|
||||
@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/<int:book_id>/<book_format>/<int:convert>')
|
||||
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user