Finish OPDS-access
This commit is contained in:
commit
e91dd5729a
|
@ -483,8 +483,10 @@ def autodetect_calibre_binaries():
|
|||
else:
|
||||
calibre_path = ["/opt/calibre/"]
|
||||
for element in calibre_path:
|
||||
supported_binary_paths = [os.path.join(element, binary) for binary in constants.SUPPORTED_CALIBRE_BINARIES.values()]
|
||||
if all(os.path.isfile(binary_path) and os.access(binary_path, os.X_OK) for binary_path in supported_binary_paths):
|
||||
supported_binary_paths = [os.path.join(element, binary)
|
||||
for binary in constants.SUPPORTED_CALIBRE_BINARIES.values()]
|
||||
if all(os.path.isfile(binary_path) and os.access(binary_path, os.X_OK)
|
||||
for binary_path in supported_binary_paths):
|
||||
values = [process_wait([binary_path, "--version"],
|
||||
pattern=r'\(calibre (.*)\)') for binary_path in supported_binary_paths]
|
||||
if all(values):
|
||||
|
|
43
cps/opds.py
43
cps/opds.py
|
@ -24,14 +24,14 @@ import datetime
|
|||
import json
|
||||
from urllib.parse import unquote_plus
|
||||
|
||||
from flask import Blueprint, request, render_template, make_response, abort, Response
|
||||
from flask import Blueprint, request, render_template, make_response, abort, Response, g
|
||||
from flask_login import current_user
|
||||
from flask_babel import get_locale
|
||||
from flask_babel import gettext as _
|
||||
from sqlalchemy.sql.expression import func, text, or_, and_, true
|
||||
from sqlalchemy.exc import InvalidRequestError, OperationalError
|
||||
|
||||
from . import logger, config, db, calibre_db, ub, isoLanguages
|
||||
from . import logger, config, db, calibre_db, ub, isoLanguages, constants
|
||||
from .usermanagement import requires_basic_auth_if_no_ano
|
||||
from .helper import get_download_link, get_book_cover
|
||||
from .pagination import Pagination
|
||||
|
@ -94,6 +94,8 @@ def feed_letter_books(book_id):
|
|||
@opds.route("/opds/new")
|
||||
@requires_basic_auth_if_no_ano
|
||||
def feed_new():
|
||||
if not current_user.check_visibility(constants.SIDEBAR_RECENT):
|
||||
abort(404)
|
||||
off = request.args.get("offset") or 0
|
||||
entries, __, pagination = calibre_db.fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), 0,
|
||||
db.Books, True, [db.Books.timestamp.desc()],
|
||||
|
@ -104,6 +106,8 @@ def feed_new():
|
|||
@opds.route("/opds/discover")
|
||||
@requires_basic_auth_if_no_ano
|
||||
def feed_discover():
|
||||
if not current_user.check_visibility(constants.SIDEBAR_RANDOM):
|
||||
abort(404)
|
||||
query = calibre_db.generate_linked_query(config.config_read_column, db.Books)
|
||||
entries = query.filter(calibre_db.common_filters()).order_by(func.random()).limit(config.config_books_per_page)
|
||||
pagination = Pagination(1, config.config_books_per_page, int(config.config_books_per_page))
|
||||
|
@ -113,6 +117,8 @@ def feed_discover():
|
|||
@opds.route("/opds/rated")
|
||||
@requires_basic_auth_if_no_ano
|
||||
def feed_best_rated():
|
||||
if not current_user.check_visibility(constants.SIDEBAR_BEST_RATED):
|
||||
abort(404)
|
||||
off = request.args.get("offset") or 0
|
||||
entries, __, pagination = calibre_db.fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), 0,
|
||||
db.Books, db.Books.ratings.any(db.Ratings.rating > 9),
|
||||
|
@ -124,6 +130,8 @@ def feed_best_rated():
|
|||
@opds.route("/opds/hot")
|
||||
@requires_basic_auth_if_no_ano
|
||||
def feed_hot():
|
||||
if not current_user.check_visibility(constants.SIDEBAR_HOT):
|
||||
abort(404)
|
||||
off = request.args.get("offset") or 0
|
||||
all_books = ub.session.query(ub.Downloads, func.count(ub.Downloads.book_id)).order_by(
|
||||
func.count(ub.Downloads.book_id).desc()).group_by(ub.Downloads.book_id)
|
||||
|
@ -146,12 +154,16 @@ def feed_hot():
|
|||
@opds.route("/opds/author")
|
||||
@requires_basic_auth_if_no_ano
|
||||
def feed_authorindex():
|
||||
if not current_user.check_visibility(constants.SIDEBAR_AUTHOR):
|
||||
abort(404)
|
||||
return render_element_index(db.Authors.sort, db.books_authors_link, 'opds.feed_letter_author')
|
||||
|
||||
|
||||
@opds.route("/opds/author/letter/<book_id>")
|
||||
@requires_basic_auth_if_no_ano
|
||||
def feed_letter_author(book_id):
|
||||
if not current_user.check_visibility(constants.SIDEBAR_AUTHOR):
|
||||
abort(404)
|
||||
off = request.args.get("offset") or 0
|
||||
letter = true() if book_id == "00" else func.upper(db.Authors.sort).startswith(book_id)
|
||||
entries = calibre_db.session.query(db.Authors).join(db.books_authors_link).join(db.Books)\
|
||||
|
@ -173,6 +185,8 @@ def feed_author(book_id):
|
|||
@opds.route("/opds/publisher")
|
||||
@requires_basic_auth_if_no_ano
|
||||
def feed_publisherindex():
|
||||
if not current_user.check_visibility(constants.SIDEBAR_PUBLISHER):
|
||||
abort(404)
|
||||
off = request.args.get("offset") or 0
|
||||
entries = calibre_db.session.query(db.Publishers)\
|
||||
.join(db.books_publishers_link)\
|
||||
|
@ -194,12 +208,16 @@ def feed_publisher(book_id):
|
|||
@opds.route("/opds/category")
|
||||
@requires_basic_auth_if_no_ano
|
||||
def feed_categoryindex():
|
||||
if not current_user.check_visibility(constants.SIDEBAR_CATEGORY):
|
||||
abort(404)
|
||||
return render_element_index(db.Tags.name, db.books_tags_link, 'opds.feed_letter_category')
|
||||
|
||||
|
||||
@opds.route("/opds/category/letter/<book_id>")
|
||||
@requires_basic_auth_if_no_ano
|
||||
def feed_letter_category(book_id):
|
||||
if not current_user.check_visibility(constants.SIDEBAR_CATEGORY):
|
||||
abort(404)
|
||||
off = request.args.get("offset") or 0
|
||||
letter = true() if book_id == "00" else func.upper(db.Tags.name).startswith(book_id)
|
||||
entries = calibre_db.session.query(db.Tags)\
|
||||
|
@ -223,12 +241,16 @@ def feed_category(book_id):
|
|||
@opds.route("/opds/series")
|
||||
@requires_basic_auth_if_no_ano
|
||||
def feed_seriesindex():
|
||||
if not current_user.check_visibility(constants.SIDEBAR_SERIES):
|
||||
abort(404)
|
||||
return render_element_index(db.Series.sort, db.books_series_link, 'opds.feed_letter_series')
|
||||
|
||||
|
||||
@opds.route("/opds/series/letter/<book_id>")
|
||||
@requires_basic_auth_if_no_ano
|
||||
def feed_letter_series(book_id):
|
||||
if not current_user.check_visibility(constants.SIDEBAR_SERIES):
|
||||
abort(404)
|
||||
off = request.args.get("offset") or 0
|
||||
letter = true() if book_id == "00" else func.upper(db.Series.sort).startswith(book_id)
|
||||
entries = calibre_db.session.query(db.Series)\
|
||||
|
@ -258,6 +280,8 @@ def feed_series(book_id):
|
|||
@opds.route("/opds/ratings")
|
||||
@requires_basic_auth_if_no_ano
|
||||
def feed_ratingindex():
|
||||
if not current_user.check_visibility(constants.SIDEBAR_RATING):
|
||||
abort(404)
|
||||
off = request.args.get("offset") or 0
|
||||
entries = calibre_db.session.query(db.Ratings, func.count('books_ratings_link.book').label('count'),
|
||||
(db.Ratings.rating / 2).label('name')) \
|
||||
|
@ -284,6 +308,8 @@ def feed_ratings(book_id):
|
|||
@opds.route("/opds/formats")
|
||||
@requires_basic_auth_if_no_ano
|
||||
def feed_formatindex():
|
||||
if not current_user.check_visibility(constants.SIDEBAR_FORMAT):
|
||||
abort(404)
|
||||
off = request.args.get("offset") or 0
|
||||
entries = calibre_db.session.query(db.Data).join(db.Books)\
|
||||
.filter(calibre_db.common_filters()) \
|
||||
|
@ -291,7 +317,6 @@ def feed_formatindex():
|
|||
.order_by(db.Data.format).all()
|
||||
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
|
||||
len(entries))
|
||||
|
||||
element = list()
|
||||
for entry in entries:
|
||||
element.append(FeedObject(entry.format, entry.format))
|
||||
|
@ -314,6 +339,8 @@ def feed_format(book_id):
|
|||
@opds.route("/opds/language/")
|
||||
@requires_basic_auth_if_no_ano
|
||||
def feed_languagesindex():
|
||||
if not current_user.check_visibility(constants.SIDEBAR_LANGUAGE):
|
||||
abort(404)
|
||||
off = request.args.get("offset") or 0
|
||||
if current_user.filter_language() == "all":
|
||||
languages = calibre_db.speaking_language()
|
||||
|
@ -341,6 +368,8 @@ def feed_languages(book_id):
|
|||
@opds.route("/opds/shelfindex")
|
||||
@requires_basic_auth_if_no_ano
|
||||
def feed_shelfindex():
|
||||
if not (current_user.is_authenticated or g.allow_anonymous):
|
||||
abort(404)
|
||||
off = request.args.get("offset") or 0
|
||||
shelf = ub.session.query(ub.Shelf).filter(
|
||||
or_(ub.Shelf.is_public == 1, ub.Shelf.user_id == current_user.id)).order_by(ub.Shelf.name).all()
|
||||
|
@ -353,6 +382,8 @@ def feed_shelfindex():
|
|||
@opds.route("/opds/shelf/<int:book_id>")
|
||||
@requires_basic_auth_if_no_ano
|
||||
def feed_shelf(book_id):
|
||||
if not (current_user.is_authenticated or g.allow_anonymous):
|
||||
abort(404)
|
||||
off = request.args.get("offset") or 0
|
||||
if current_user.is_anonymous:
|
||||
shelf = ub.session.query(ub.Shelf).filter(ub.Shelf.is_public == 1,
|
||||
|
@ -436,6 +467,8 @@ def feed_get_cover(book_id):
|
|||
@opds.route("/opds/readbooks")
|
||||
@requires_basic_auth_if_no_ano
|
||||
def feed_read_books():
|
||||
if not (current_user.check_visibility(constants.SIDEBAR_READ_AND_UNREAD) and not current_user.is_anonymous):
|
||||
return abort(403)
|
||||
off = request.args.get("offset") or 0
|
||||
result, pagination = render_read_books(int(off) / (int(config.config_books_per_page)) + 1, True, True)
|
||||
return render_xml_template('feed.xml', entries=result, pagination=pagination)
|
||||
|
@ -444,6 +477,8 @@ def feed_read_books():
|
|||
@opds.route("/opds/unreadbooks")
|
||||
@requires_basic_auth_if_no_ano
|
||||
def feed_unread_books():
|
||||
if not (current_user.check_visibility(constants.SIDEBAR_READ_AND_UNREAD) and not current_user.is_anonymous):
|
||||
return abort(403)
|
||||
off = request.args.get("offset") or 0
|
||||
result, pagination = render_read_books(int(off) / (int(config.config_books_per_page)) + 1, False, True)
|
||||
return render_xml_template('feed.xml', entries=result, pagination=pagination)
|
||||
|
@ -477,7 +512,7 @@ def feed_search(term):
|
|||
def render_xml_template(*args, **kwargs):
|
||||
# ToDo: return time in current timezone similar to %z
|
||||
currtime = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S+00:00")
|
||||
xml = render_template(current_time=currtime, instance=config.config_calibre_web_title, *args, **kwargs)
|
||||
xml = render_template(current_time=currtime, instance=config.config_calibre_web_title, constants=constants.sidebar_settings, *args, **kwargs)
|
||||
response = make_response(xml)
|
||||
response.headers["Content-Type"] = "application/atom+xml; charset=utf-8"
|
||||
return response
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
<updated>{{ current_time }}</updated>
|
||||
<content type="text">{{_('Books sorted alphabetically')}}</content>
|
||||
</entry>
|
||||
{% if current_user.check_visibility(g.constants.SIDEBAR_HOT) %}
|
||||
<entry>
|
||||
<title>{{_('Hot Books')}}</title>
|
||||
<link href="{{url_for('opds.feed_hot')}}" type="application/atom+xml;profile=opds-catalog"/>
|
||||
|
@ -29,6 +30,8 @@
|
|||
<updated>{{ current_time }}</updated>
|
||||
<content type="text">{{_('Popular publications from this catalog based on Downloads.')}}</content>
|
||||
</entry>
|
||||
{%endif %}
|
||||
{% if current_user.check_visibility(g.constants.SIDEBAR_BEST_RATED) %}
|
||||
<entry>
|
||||
<title>{{_('Top Rated Books')}}</title>
|
||||
<link href="{{url_for('opds.feed_best_rated')}}" type="application/atom+xml;profile=opds-catalog"/>
|
||||
|
@ -36,6 +39,8 @@
|
|||
<updated>{{ current_time }}</updated>
|
||||
<content type="text">{{_('Popular publications from this catalog based on Rating.')}}</content>
|
||||
</entry>
|
||||
{%endif %}
|
||||
{% if current_user.check_visibility(g.constants.SIDEBAR_RECENT) %}
|
||||
<entry>
|
||||
<title>{{_('Recently added Books')}}</title>
|
||||
<link href="{{url_for('opds.feed_new')}}" type="application/atom+xml;profile=opds-catalog"/>
|
||||
|
@ -43,6 +48,8 @@
|
|||
<updated>{{ current_time }}</updated>
|
||||
<content type="text">{{_('The latest Books')}}</content>
|
||||
</entry>
|
||||
{%endif %}
|
||||
{% if current_user.check_visibility(g.constants.SIDEBAR_RANDOM) %}
|
||||
<entry>
|
||||
<title>{{_('Random Books')}}</title>
|
||||
<link href="{{url_for('opds.feed_discover')}}" type="application/atom+xml;profile=opds-catalog"/>
|
||||
|
@ -50,7 +57,8 @@
|
|||
<updated>{{ current_time }}</updated>
|
||||
<content type="text">{{_('Show Random Books')}}</content>
|
||||
</entry>
|
||||
{% if not current_user.is_anonymous %}
|
||||
{%endif %}
|
||||
{% if current_user.check_visibility(g.constants.SIDEBAR_READ_AND_UNREAD) and not current_user.is_anonymous %}
|
||||
<entry>
|
||||
<title>{{_('Read Books')}}</title>
|
||||
<link href="{{url_for('opds.feed_read_books')}}" type="application/atom+xml;profile=opds-catalog"/>
|
||||
|
@ -66,6 +74,7 @@
|
|||
<content type="text">{{_('Unread Books')}}</content>
|
||||
</entry>
|
||||
{% endif %}
|
||||
{% if current_user.check_visibility(g.constants.SIDEBAR_AUTHOR) %}
|
||||
<entry>
|
||||
<title>{{_('Authors')}}</title>
|
||||
<link href="{{url_for('opds.feed_authorindex')}}" type="application/atom+xml;profile=opds-catalog"/>
|
||||
|
@ -73,13 +82,17 @@
|
|||
<updated>{{ current_time }}</updated>
|
||||
<content type="text">{{_('Books ordered by Author')}}</content>
|
||||
</entry>
|
||||
<entry>
|
||||
{% endif %}
|
||||
{% if current_user.check_visibility(g.constants.SIDEBAR_PUBLISHER) %}
|
||||
<entry>
|
||||
<title>{{_('Publishers')}}</title>
|
||||
<link href="{{url_for('opds.feed_publisherindex')}}" type="application/atom+xml;profile=opds-catalog"/>
|
||||
<id>{{url_for('opds.feed_publisherindex')}}</id>
|
||||
<updated>{{ current_time }}</updated>
|
||||
<content type="text">{{_('Books ordered by publisher')}}</content>
|
||||
</entry>
|
||||
{% endif %}
|
||||
{% if current_user.check_visibility(g.constants.SIDEBAR_CATEGORY) %}
|
||||
<entry>
|
||||
<title>{{_('Categories')}}</title>
|
||||
<link href="{{url_for('opds.feed_categoryindex')}}" type="application/atom+xml;profile=opds-catalog"/>
|
||||
|
@ -87,6 +100,8 @@
|
|||
<updated>{{ current_time }}</updated>
|
||||
<content type="text">{{_('Books ordered by category')}}</content>
|
||||
</entry>
|
||||
{% endif %}
|
||||
{% if current_user.check_visibility(g.constants.SIDEBAR_SERIES) %}
|
||||
<entry>
|
||||
<title>{{_('Series')}}</title>
|
||||
<link href="{{url_for('opds.feed_seriesindex')}}" type="application/atom+xml;profile=opds-catalog"/>
|
||||
|
@ -94,6 +109,8 @@
|
|||
<updated>{{ current_time }}</updated>
|
||||
<content type="text">{{_('Books ordered by series')}}</content>
|
||||
</entry>
|
||||
{% endif %}
|
||||
{% if current_user.check_visibility(g.constants.SIDEBAR_LANGUAGE) %}
|
||||
<entry>
|
||||
<title>{{_('Languages')}}</title>
|
||||
<link href="{{url_for('opds.feed_languagesindex')}}" type="application/atom+xml;profile=opds-catalog"/>
|
||||
|
@ -101,6 +118,8 @@
|
|||
<updated>{{ current_time }}</updated>
|
||||
<content type="text">{{_('Books ordered by Languages')}}</content>
|
||||
</entry>
|
||||
{% endif %}
|
||||
{% if current_user.check_visibility(g.constants.SIDEBAR_RATING) %}
|
||||
<entry>
|
||||
<title>{{_('Ratings')}}</title>
|
||||
<link href="{{url_for('opds.feed_ratingindex')}}" type="application/atom+xml;profile=opds-catalog"/>
|
||||
|
@ -108,7 +127,8 @@
|
|||
<updated>{{ current_time }}</updated>
|
||||
<content type="text">{{_('Books ordered by Rating')}}</content>
|
||||
</entry>
|
||||
|
||||
{% endif %}
|
||||
{% if current_user.check_visibility(g.constants.SIDEBAR_FORMAT) %}
|
||||
<entry>
|
||||
<title>{{_('File formats')}}</title>
|
||||
<link href="{{url_for('opds.feed_formatindex')}}" type="application/atom+xml;profile=opds-catalog"/>
|
||||
|
@ -116,6 +136,8 @@
|
|||
<updated>{{ current_time }}</updated>
|
||||
<content type="text">{{_('Books ordered by file formats')}}</content>
|
||||
</entry>
|
||||
{% endif %}
|
||||
{% if current_user.is_authenticated or g.allow_anonymous %}
|
||||
<entry>
|
||||
<title>{{_('Shelves')}}</title>
|
||||
<link href="{{url_for('opds.feed_shelfindex')}}" type="application/atom+xml;profile=opds-catalog"/>
|
||||
|
@ -123,4 +145,5 @@
|
|||
<updated>{{ current_time }}</updated>
|
||||
<content type="text">{{_('Books organized in shelves')}}</content>
|
||||
</entry>
|
||||
{% endif %}
|
||||
</feed>
|
||||
|
|
|
@ -5,8 +5,8 @@ greenlet>=0.4.17,<3.1.0
|
|||
httplib2>=0.9.2,<0.23.0
|
||||
oauth2client>=4.0.0,<4.1.4
|
||||
uritemplate>=3.0.0,<4.2.0
|
||||
pyasn1-modules>=0.0.8,<0.4.0
|
||||
pyasn1>=0.1.9,<0.6.0
|
||||
pyasn1-modules>=0.0.8,<0.5.0
|
||||
pyasn1>=0.1.9,<0.7.0
|
||||
PyDrive2>=1.3.1,<1.20.0
|
||||
PyYAML>=3.12,<6.1
|
||||
rsa>=3.4.2,<4.10.0
|
||||
|
@ -28,11 +28,11 @@ Flask-Dance>=2.0.0,<7.1.0
|
|||
SQLAlchemy-Utils>=0.33.5,<0.42.0
|
||||
|
||||
# metadata extraction
|
||||
rarfile>=3.2,<4.2
|
||||
rarfile>=3.2,<5.0
|
||||
scholarly>=1.2.0,<1.8
|
||||
markdown2>=2.0.0,<2.5.0
|
||||
html2text>=2020.1.16,<2024.2.26
|
||||
python-dateutil>=2.1,<2.9.0
|
||||
python-dateutil>=2.1,<2.10.0
|
||||
beautifulsoup4>=4.0.1,<4.13.0
|
||||
faust-cchardet>=2.1.18,<2.1.20
|
||||
py7zr>=0.15.0,<0.21.0
|
||||
|
@ -42,4 +42,4 @@ natsort>=2.2.0,<8.5.0
|
|||
comicapi>=2.2.0,<3.3.0
|
||||
|
||||
# Kobo integration
|
||||
jsonschema>=3.2.0,<4.22.0
|
||||
jsonschema>=3.2.0,<4.23.0
|
||||
|
|
10
setup.cfg
10
setup.cfg
|
@ -73,8 +73,8 @@ gdrive =
|
|||
httplib2>=0.9.2,<0.23.0
|
||||
oauth2client>=4.0.0,<4.1.4
|
||||
uritemplate>=3.0.0,<4.2.0
|
||||
pyasn1-modules>=0.0.8,<0.4.0
|
||||
pyasn1>=0.1.9,<0.6.0
|
||||
pyasn1-modules>=0.0.8,<0.5.0
|
||||
pyasn1>=0.1.9,<0.7.0
|
||||
PyDrive2>=1.3.1,<1.20.0
|
||||
PyYAML>=3.12,<6.1
|
||||
rsa>=3.4.2,<4.10.0
|
||||
|
@ -91,11 +91,11 @@ oauth =
|
|||
Flask-Dance>=2.0.0,<7.1.0
|
||||
SQLAlchemy-Utils>=0.33.5,<0.42.0
|
||||
metadata =
|
||||
rarfile>=3.2,<4.2
|
||||
rarfile>=3.2,<5.0
|
||||
scholarly>=1.2.0,<1.8
|
||||
markdown2>=2.0.0,<2.5.0
|
||||
html2text>=2020.1.16,<2024.2.26
|
||||
python-dateutil>=2.1,<2.9.0
|
||||
python-dateutil>=2.1,<2.10.0
|
||||
beautifulsoup4>=4.0.1,<4.13.0
|
||||
faust-cchardet>=2.1.18,<2.1.20
|
||||
py7zr>=0.15.0,<0.21.0
|
||||
|
@ -103,5 +103,5 @@ comics =
|
|||
natsort>=2.2.0,<8.5.0
|
||||
comicapi>=2.2.0,<3.3.0
|
||||
kobo =
|
||||
jsonschema>=3.2.0,<4.22.0
|
||||
jsonschema>=3.2.0,<4.23.0
|
||||
|
||||
|
|
|
@ -37,20 +37,20 @@
|
|||
<div class="row">
|
||||
<div class="col-xs-6 col-md-6 col-sm-offset-3" style="margin-top:50px;">
|
||||
|
||||
<p class='text-justify attribute'><strong>Start Time: </strong>2024-05-10 20:24:40</p>
|
||||
<p class='text-justify attribute'><strong>Start Time: </strong>2024-05-11 18:39:24</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6 col-md-6 col-sm-offset-3">
|
||||
|
||||
<p class='text-justify attribute'><strong>Stop Time: </strong>2024-05-11 03:33:47</p>
|
||||
<p class='text-justify attribute'><strong>Stop Time: </strong>2024-05-12 01:48:22</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6 col-md-6 col-sm-offset-3">
|
||||
<p class='text-justify attribute'><strong>Duration: </strong>5h 58 min</p>
|
||||
<p class='text-justify attribute'><strong>Duration: </strong>5h 59 min</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -234,11 +234,11 @@
|
|||
|
||||
|
||||
|
||||
<tr id="su" class="failClass">
|
||||
<tr id="su" class="passClass">
|
||||
<td>TestBackupMetadata</td>
|
||||
<td class="text-center">21</td>
|
||||
<td class="text-center">20</td>
|
||||
<td class="text-center">1</td>
|
||||
<td class="text-center">21</td>
|
||||
<td class="text-center">0</td>
|
||||
<td class="text-center">0</td>
|
||||
<td class="text-center">0</td>
|
||||
<td class="text-center">
|
||||
|
@ -320,35 +320,11 @@
|
|||
|
||||
|
||||
|
||||
<tr id="ft2.9" class="none bg-danger">
|
||||
<tr id='pt2.9' class='hiddenRow bg-success'>
|
||||
<td>
|
||||
<div class='testcase'>TestBackupMetadata - test_backup_change_book_series_index</div>
|
||||
</td>
|
||||
<td colspan='6'>
|
||||
<div class="text-center">
|
||||
<a class="popup_link text-center" onfocus='blur()' onclick="showTestDetail('div_ft2.9')">FAIL</a>
|
||||
</div>
|
||||
<!--css div popup start-->
|
||||
<div id="div_ft2.9" class="popup_window test_output" style="display:block;">
|
||||
<div class='close_button pull-right'>
|
||||
<button type="button" class="close" aria-label="Close" onfocus="this.blur();"
|
||||
onclick="document.getElementById('div_ft2.9').style.display='none'"><span
|
||||
aria-hidden="true">×</span></button>
|
||||
</div>
|
||||
<div class="text-left pull-left">
|
||||
<pre class="text-left">Traceback (most recent call last):
|
||||
File "/home/ozzie/Development/calibre-web-test/test/test_backup_metadata.py", line 135, in test_backup_change_book_series_index
|
||||
self.assertEqual(metadata['series']['content'], "tEst")
|
||||
AssertionError: 'test' != 'tEst'
|
||||
- test
|
||||
? ^
|
||||
+ tEst
|
||||
? ^</pre>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
<!--css div popup end-->
|
||||
</td>
|
||||
<td colspan='6' align='center'>PASS</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
@ -2594,11 +2570,11 @@ IndexError: list index out of range</pre>
|
|||
|
||||
|
||||
|
||||
<tr id="su" class="failClass">
|
||||
<tr id="su" class="passClass">
|
||||
<td>TestGoodreads</td>
|
||||
<td class="text-center">3</td>
|
||||
<td class="text-center">2</td>
|
||||
<td class="text-center">1</td>
|
||||
<td class="text-center">3</td>
|
||||
<td class="text-center">0</td>
|
||||
<td class="text-center">0</td>
|
||||
<td class="text-center">0</td>
|
||||
<td class="text-center">
|
||||
|
@ -2608,31 +2584,11 @@ IndexError: list index out of range</pre>
|
|||
|
||||
|
||||
|
||||
<tr id="ft28.1" class="none bg-danger">
|
||||
<tr id='pt28.1' class='hiddenRow bg-success'>
|
||||
<td>
|
||||
<div class='testcase'>TestGoodreads - test_author_page</div>
|
||||
</td>
|
||||
<td colspan='6'>
|
||||
<div class="text-center">
|
||||
<a class="popup_link text-center" onfocus='blur()' onclick="showTestDetail('div_ft28.1')">FAIL</a>
|
||||
</div>
|
||||
<!--css div popup start-->
|
||||
<div id="div_ft28.1" class="popup_window test_output" style="display:block;">
|
||||
<div class='close_button pull-right'>
|
||||
<button type="button" class="close" aria-label="Close" onfocus="this.blur();"
|
||||
onclick="document.getElementById('div_ft28.1').style.display='none'"><span
|
||||
aria-hidden="true">×</span></button>
|
||||
</div>
|
||||
<div class="text-left pull-left">
|
||||
<pre class="text-left">Traceback (most recent call last):
|
||||
File "/home/ozzie/Development/calibre-web-test/test/test_goodreads.py", line 100, in test_author_page
|
||||
self.assertTrue(self.check_element_on_page((By.CLASS_NAME, "author-photo")))
|
||||
AssertionError: False is not true</pre>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
<!--css div popup end-->
|
||||
</td>
|
||||
<td colspan='6' align='center'>PASS</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
@ -3577,13 +3533,13 @@ AssertionError: False is not true</pre>
|
|||
|
||||
<tr id="su" class="passClass">
|
||||
<td>TestOPDSFeed</td>
|
||||
<td class="text-center">24</td>
|
||||
<td class="text-center">24</td>
|
||||
<td class="text-center">26</td>
|
||||
<td class="text-center">26</td>
|
||||
<td class="text-center">0</td>
|
||||
<td class="text-center">0</td>
|
||||
<td class="text-center">0</td>
|
||||
<td class="text-center">
|
||||
<a onclick="showClassDetail('c38', 24)">Detail</a>
|
||||
<a onclick="showClassDetail('c38', 26)">Detail</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
@ -3591,7 +3547,7 @@ AssertionError: False is not true</pre>
|
|||
|
||||
<tr id='pt38.1' class='hiddenRow bg-success'>
|
||||
<td>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds</div>
|
||||
<div class='testcase'>TestOPDSFeed - test_access_right_guest</div>
|
||||
</td>
|
||||
<td colspan='6' align='center'>PASS</td>
|
||||
</tr>
|
||||
|
@ -3600,7 +3556,7 @@ AssertionError: False is not true</pre>
|
|||
|
||||
<tr id='pt38.2' class='hiddenRow bg-success'>
|
||||
<td>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_author</div>
|
||||
<div class='testcase'>TestOPDSFeed - test_access_right_user</div>
|
||||
</td>
|
||||
<td colspan='6' align='center'>PASS</td>
|
||||
</tr>
|
||||
|
@ -3609,7 +3565,7 @@ AssertionError: False is not true</pre>
|
|||
|
||||
<tr id='pt38.3' class='hiddenRow bg-success'>
|
||||
<td>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_books</div>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds</div>
|
||||
</td>
|
||||
<td colspan='6' align='center'>PASS</td>
|
||||
</tr>
|
||||
|
@ -3618,7 +3574,7 @@ AssertionError: False is not true</pre>
|
|||
|
||||
<tr id='pt38.4' class='hiddenRow bg-success'>
|
||||
<td>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_calibre_companion</div>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_author</div>
|
||||
</td>
|
||||
<td colspan='6' align='center'>PASS</td>
|
||||
</tr>
|
||||
|
@ -3627,7 +3583,7 @@ AssertionError: False is not true</pre>
|
|||
|
||||
<tr id='pt38.5' class='hiddenRow bg-success'>
|
||||
<td>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_colon_password</div>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_books</div>
|
||||
</td>
|
||||
<td colspan='6' align='center'>PASS</td>
|
||||
</tr>
|
||||
|
@ -3636,7 +3592,7 @@ AssertionError: False is not true</pre>
|
|||
|
||||
<tr id='pt38.6' class='hiddenRow bg-success'>
|
||||
<td>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_cover</div>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_calibre_companion</div>
|
||||
</td>
|
||||
<td colspan='6' align='center'>PASS</td>
|
||||
</tr>
|
||||
|
@ -3645,7 +3601,7 @@ AssertionError: False is not true</pre>
|
|||
|
||||
<tr id='pt38.7' class='hiddenRow bg-success'>
|
||||
<td>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_download_book</div>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_colon_password</div>
|
||||
</td>
|
||||
<td colspan='6' align='center'>PASS</td>
|
||||
</tr>
|
||||
|
@ -3654,7 +3610,7 @@ AssertionError: False is not true</pre>
|
|||
|
||||
<tr id='pt38.8' class='hiddenRow bg-success'>
|
||||
<td>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_formats</div>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_cover</div>
|
||||
</td>
|
||||
<td colspan='6' align='center'>PASS</td>
|
||||
</tr>
|
||||
|
@ -3663,7 +3619,7 @@ AssertionError: False is not true</pre>
|
|||
|
||||
<tr id='pt38.9' class='hiddenRow bg-success'>
|
||||
<td>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_guest_user</div>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_download_book</div>
|
||||
</td>
|
||||
<td colspan='6' align='center'>PASS</td>
|
||||
</tr>
|
||||
|
@ -3672,7 +3628,7 @@ AssertionError: False is not true</pre>
|
|||
|
||||
<tr id='pt38.10' class='hiddenRow bg-success'>
|
||||
<td>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_hot</div>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_formats</div>
|
||||
</td>
|
||||
<td colspan='6' align='center'>PASS</td>
|
||||
</tr>
|
||||
|
@ -3681,7 +3637,7 @@ AssertionError: False is not true</pre>
|
|||
|
||||
<tr id='pt38.11' class='hiddenRow bg-success'>
|
||||
<td>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_language</div>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_guest_user</div>
|
||||
</td>
|
||||
<td colspan='6' align='center'>PASS</td>
|
||||
</tr>
|
||||
|
@ -3690,7 +3646,7 @@ AssertionError: False is not true</pre>
|
|||
|
||||
<tr id='pt38.12' class='hiddenRow bg-success'>
|
||||
<td>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_non_admin</div>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_hot</div>
|
||||
</td>
|
||||
<td colspan='6' align='center'>PASS</td>
|
||||
</tr>
|
||||
|
@ -3699,7 +3655,7 @@ AssertionError: False is not true</pre>
|
|||
|
||||
<tr id='pt38.13' class='hiddenRow bg-success'>
|
||||
<td>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_publisher</div>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_language</div>
|
||||
</td>
|
||||
<td colspan='6' align='center'>PASS</td>
|
||||
</tr>
|
||||
|
@ -3708,7 +3664,7 @@ AssertionError: False is not true</pre>
|
|||
|
||||
<tr id='pt38.14' class='hiddenRow bg-success'>
|
||||
<td>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_random</div>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_non_admin</div>
|
||||
</td>
|
||||
<td colspan='6' align='center'>PASS</td>
|
||||
</tr>
|
||||
|
@ -3717,7 +3673,7 @@ AssertionError: False is not true</pre>
|
|||
|
||||
<tr id='pt38.15' class='hiddenRow bg-success'>
|
||||
<td>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_ratings</div>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_publisher</div>
|
||||
</td>
|
||||
<td colspan='6' align='center'>PASS</td>
|
||||
</tr>
|
||||
|
@ -3726,7 +3682,7 @@ AssertionError: False is not true</pre>
|
|||
|
||||
<tr id='pt38.16' class='hiddenRow bg-success'>
|
||||
<td>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_read_unread</div>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_random</div>
|
||||
</td>
|
||||
<td colspan='6' align='center'>PASS</td>
|
||||
</tr>
|
||||
|
@ -3735,7 +3691,7 @@ AssertionError: False is not true</pre>
|
|||
|
||||
<tr id='pt38.17' class='hiddenRow bg-success'>
|
||||
<td>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_search</div>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_ratings</div>
|
||||
</td>
|
||||
<td colspan='6' align='center'>PASS</td>
|
||||
</tr>
|
||||
|
@ -3744,7 +3700,7 @@ AssertionError: False is not true</pre>
|
|||
|
||||
<tr id='pt38.18' class='hiddenRow bg-success'>
|
||||
<td>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_series</div>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_read_unread</div>
|
||||
</td>
|
||||
<td colspan='6' align='center'>PASS</td>
|
||||
</tr>
|
||||
|
@ -3753,7 +3709,7 @@ AssertionError: False is not true</pre>
|
|||
|
||||
<tr id='pt38.19' class='hiddenRow bg-success'>
|
||||
<td>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_shelf_access</div>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_search</div>
|
||||
</td>
|
||||
<td colspan='6' align='center'>PASS</td>
|
||||
</tr>
|
||||
|
@ -3762,7 +3718,7 @@ AssertionError: False is not true</pre>
|
|||
|
||||
<tr id='pt38.20' class='hiddenRow bg-success'>
|
||||
<td>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_stats</div>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_series</div>
|
||||
</td>
|
||||
<td colspan='6' align='center'>PASS</td>
|
||||
</tr>
|
||||
|
@ -3771,7 +3727,7 @@ AssertionError: False is not true</pre>
|
|||
|
||||
<tr id='pt38.21' class='hiddenRow bg-success'>
|
||||
<td>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_tags</div>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_shelf_access</div>
|
||||
</td>
|
||||
<td colspan='6' align='center'>PASS</td>
|
||||
</tr>
|
||||
|
@ -3780,7 +3736,7 @@ AssertionError: False is not true</pre>
|
|||
|
||||
<tr id='pt38.22' class='hiddenRow bg-success'>
|
||||
<td>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_top_rated</div>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_stats</div>
|
||||
</td>
|
||||
<td colspan='6' align='center'>PASS</td>
|
||||
</tr>
|
||||
|
@ -3789,7 +3745,7 @@ AssertionError: False is not true</pre>
|
|||
|
||||
<tr id='pt38.23' class='hiddenRow bg-success'>
|
||||
<td>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_unicode_user</div>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_tags</div>
|
||||
</td>
|
||||
<td colspan='6' align='center'>PASS</td>
|
||||
</tr>
|
||||
|
@ -3797,6 +3753,24 @@ AssertionError: False is not true</pre>
|
|||
|
||||
|
||||
<tr id='pt38.24' class='hiddenRow bg-success'>
|
||||
<td>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_top_rated</div>
|
||||
</td>
|
||||
<td colspan='6' align='center'>PASS</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr id='pt38.25' class='hiddenRow bg-success'>
|
||||
<td>
|
||||
<div class='testcase'>TestOPDSFeed - test_opds_unicode_user</div>
|
||||
</td>
|
||||
<td colspan='6' align='center'>PASS</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr id='pt38.26' class='hiddenRow bg-success'>
|
||||
<td>
|
||||
<div class='testcase'>TestOPDSFeed - test_recently_added</div>
|
||||
</td>
|
||||
|
@ -4447,11 +4421,11 @@ AssertionError: False is not true</pre>
|
|||
|
||||
|
||||
|
||||
<tr id="su" class="skipClass">
|
||||
<tr id="su" class="failClass">
|
||||
<td>TestThumbnails</td>
|
||||
<td class="text-center">8</td>
|
||||
<td class="text-center">7</td>
|
||||
<td class="text-center">0</td>
|
||||
<td class="text-center">6</td>
|
||||
<td class="text-center">1</td>
|
||||
<td class="text-center">0</td>
|
||||
<td class="text-center">1</td>
|
||||
<td class="text-center">
|
||||
|
@ -4524,11 +4498,31 @@ AssertionError: False is not true</pre>
|
|||
|
||||
|
||||
|
||||
<tr id='pt50.8' class='hiddenRow bg-success'>
|
||||
<tr id="ft50.8" class="none bg-danger">
|
||||
<td>
|
||||
<div class='testcase'>TestThumbnails - test_sideloaded_book</div>
|
||||
</td>
|
||||
<td colspan='6' align='center'>PASS</td>
|
||||
<td colspan='6'>
|
||||
<div class="text-center">
|
||||
<a class="popup_link text-center" onfocus='blur()' onclick="showTestDetail('div_ft50.8')">FAIL</a>
|
||||
</div>
|
||||
<!--css div popup start-->
|
||||
<div id="div_ft50.8" class="popup_window test_output" style="display:block;">
|
||||
<div class='close_button pull-right'>
|
||||
<button type="button" class="close" aria-label="Close" onfocus="this.blur();"
|
||||
onclick="document.getElementById('div_ft50.8').style.display='none'"><span
|
||||
aria-hidden="true">×</span></button>
|
||||
</div>
|
||||
<div class="text-left pull-left">
|
||||
<pre class="text-left">Traceback (most recent call last):
|
||||
File "/home/ozzie/Development/calibre-web-test/test/test_thumbnails.py", line 326, in test_sideloaded_book
|
||||
self.assertGreaterEqual(diff(BytesIO(list_cover), BytesIO(new_list_cover), delete_diff_file=True), 0.04)
|
||||
AssertionError: 0.03372577030812325 not greater than or equal to 0.04</pre>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
<!--css div popup end-->
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
@ -5611,9 +5605,9 @@ AssertionError: False is not true</pre>
|
|||
|
||||
<tr id='total_row' class="text-center bg-grey">
|
||||
<td>Total</td>
|
||||
<td>492</td>
|
||||
<td>477</td>
|
||||
<td>4</td>
|
||||
<td>494</td>
|
||||
<td>480</td>
|
||||
<td>3</td>
|
||||
<td>1</td>
|
||||
<td>10</td>
|
||||
<td> </td>
|
||||
|
@ -5799,7 +5793,7 @@ AssertionError: False is not true</pre>
|
|||
|
||||
<tr>
|
||||
<th>google-api-python-client</th>
|
||||
<td>2.128.0</td>
|
||||
<td>2.129.0</td>
|
||||
<td>TestBackupMetadataGdrive</td>
|
||||
</tr>
|
||||
|
||||
|
@ -5829,7 +5823,7 @@ AssertionError: False is not true</pre>
|
|||
|
||||
<tr>
|
||||
<th>google-api-python-client</th>
|
||||
<td>2.128.0</td>
|
||||
<td>2.129.0</td>
|
||||
<td>TestCliGdrivedb</td>
|
||||
</tr>
|
||||
|
||||
|
@ -5859,7 +5853,7 @@ AssertionError: False is not true</pre>
|
|||
|
||||
<tr>
|
||||
<th>google-api-python-client</th>
|
||||
<td>2.128.0</td>
|
||||
<td>2.129.0</td>
|
||||
<td>TestEbookConvertCalibreGDrive</td>
|
||||
</tr>
|
||||
|
||||
|
@ -6141,7 +6135,7 @@ AssertionError: False is not true</pre>
|
|||
</div>
|
||||
|
||||
<script>
|
||||
drawCircle(477, 4, 1, 10);
|
||||
drawCircle(480, 3, 1, 10);
|
||||
showCase(5);
|
||||
</script>
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user