Merge branch 'Develop'

This commit is contained in:
Ozzie Isaacs
2026-05-24 10:20:42 +02:00
11 changed files with 232 additions and 2017 deletions

View File

@@ -36,7 +36,12 @@ def clean_string(unsafe_text, book_id=0):
if bleach: if bleach:
allowed_tags = list(ALLOWED_TAGS) allowed_tags = list(ALLOWED_TAGS)
allowed_tags.extend(["p", "span", "div", "pre", "br", "h1", "h2", "h3", "h4", "h5", "h6", "img"]) allowed_tags.extend(["p", "span", "div", "pre", "br", "h1", "h2", "h3", "h4", "h5", "h6", "img"])
safe_text = clean_html(unsafe_text, tags=set(allowed_tags)) allowed_attributes = {
"*": ["class", "style"],
"a": ["href", "title", "rel"],
"img": ["src", "alt", "title", "width", "height"],
}
safe_text = clean_html(unsafe_text, tags=set(allowed_tags), attributes=allowed_attributes)
else: else:
safe_text = clean_html(unsafe_text) safe_text = clean_html(unsafe_text)
except ParserError as e: except ParserError as e:

View File

@@ -753,7 +753,8 @@ class CalibreDB:
.filter(self.common_filters(allow_show_archived)).first()) .filter(self.common_filters(allow_show_archived)).first())
def get_book_by_uuid(self, book_uuid): def get_book_by_uuid(self, book_uuid):
return self.session.query(Books).filter(Books.uuid == book_uuid).first() return self.session.query(Books).filter(Books.uuid == book_uuid). \
filter(self.common_filters()).first()
def get_book_format(self, book_id, file_format): def get_book_format(self, book_id, file_format):
return self.session.query(Data).filter(Data.book == book_id).filter(Data.format == file_format).first() return self.session.query(Data).filter(Data.book == book_id).filter(Data.format == file_format).first()
@@ -1125,7 +1126,7 @@ class CalibreDB:
.filter(self.common_filters()) .filter(self.common_filters())
.count()) .count())
if no_lang_count: if no_lang_count:
tags.append([Category(_("None"), None, "none"), no_lang_count]) tags.append([Category(_("None"), "None", "none"), no_lang_count])
return sorted(tags, key=lambda x: x[0].name.lower(), reverse=reverse_order) return sorted(tags, key=lambda x: x[0].name.lower(), reverse=reverse_order)
else: else:
if not languages: if not languages:

View File

@@ -41,7 +41,7 @@ except ImportError:
VERSION = 'Tornado ' + _version VERSION = 'Tornado ' + _version
_GEVENT = False _GEVENT = False
from . import logger from . import logger, constants
log = logger.create() log = logger.create()
@@ -216,9 +216,10 @@ class WebServer(object):
try: try:
sock, output = self._make_gevent_listener() sock, output = self._make_gevent_listener()
log.info('Starting Gevent server on %s', output) log.info('Starting Gevent server on %s', output)
# Also print to stdout so interactive terminals show a clear success message
try: try:
print(f"Calibre-Web: server started on {output}") # Also print to stdout so interactive terminals show a clear success message
if constants.APP_MODE not in ['development', 'test']:
print(f"Calibre-Web: server started on {output}")
except Exception: except Exception:
print(f"Calibre-Web: error {output}") print(f"Calibre-Web: error {output}")
pass pass
@@ -274,7 +275,8 @@ class WebServer(object):
log.info('Starting Tornado server on %s', output) log.info('Starting Tornado server on %s', output)
# Also print to stdout so interactive terminals show a clear success message # Also print to stdout so interactive terminals show a clear success message
try: try:
print(f"Calibre-Web: server started on {output}") if constants.APP_MODE not in ['development', 'test']:
print(f"Calibre-Web: server started on {output}")
except Exception: except Exception:
print(f"Calibre-Web: error {output}") print(f"Calibre-Web: error {output}")
pass pass

View File

@@ -232,7 +232,7 @@
{% elif c.datatype == 'datetime' %} {% elif c.datatype == 'datetime' %}
{{ column.value|formatdate }} {{ column.value|formatdate }}
{% elif c.datatype == 'comments' %} {% elif c.datatype == 'comments' %}
{{ column.value|safe }} {{ column.value|clean_string|safe }}
{% elif c.datatype == 'series' %} {% elif c.datatype == 'series' %}
{{ '%s [%s]' % (column.value, column.extra|formatfloat(2)) }} {{ '%s [%s]' % (column.value, column.extra|formatfloat(2)) }}
{% elif c.datatype == 'text' %} {% elif c.datatype == 'text' %}

View File

@@ -94,7 +94,7 @@
{% elif c.datatype == 'datetime' %} {% elif c.datatype == 'datetime' %}
{{ column.value|formatdate }} {{ column.value|formatdate }}
{% elif c.datatype == 'comments' %} {% elif c.datatype == 'comments' %}
{{ column.value|safe }} {{ column.value|clean_string|safe }}
{% elif c.datatype == 'series' %} {% elif c.datatype == 'series' %}
{{ '%s [%s]' % (column.value, column.extra|formatfloat(2)) }} {{ '%s [%s]' % (column.value, column.extra|formatfloat(2)) }}
{% elif c.datatype == 'text' %} {% elif c.datatype == 'text' %}

View File

@@ -134,7 +134,7 @@
{% elif c.datatype == 'datetime' %} {% elif c.datatype == 'datetime' %}
{{ column.value|formatdate }} {{ column.value|formatdate }}
{% elif c.datatype == 'comments' %} {% elif c.datatype == 'comments' %}
{{column.value|safe}} {{column.value|clean_string|safe}}
{% elif c.datatype == 'series' %} {% elif c.datatype == 'series' %}
{{ '%s [%s]' % (column.value, column.extra|formatfloat(2)) }} {{ '%s [%s]' % (column.value, column.extra|formatfloat(2)) }}
{% elif c.datatype == 'text' %} {% elif c.datatype == 'text' %}

View File

@@ -537,7 +537,7 @@ class RemoteAuthToken(Base):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.auth_token = (hexlify(os.urandom(4))).decode('utf-8') self.auth_token = (hexlify(os.urandom(16))).decode('utf-8')
self.expiration = datetime.now() + timedelta(minutes=10) # 10 min from now self.expiration = datetime.now() + timedelta(minutes=10) # 10 min from now
def __repr__(self): def __repr__(self):

View File

@@ -711,7 +711,7 @@ def render_language_books(page, name, order):
lang_name = _("None") lang_name = _("None")
except KeyError: except KeyError:
abort(404) abort(404)
if name == "none": if name.lower() == "none":
entries, random, pagination = calibre_db.fill_indexpage(page, 0, entries, random, pagination = calibre_db.fill_indexpage(page, 0,
db.Books, db.Books,
db.Languages.lang_code == None, db.Languages.lang_code == None,

View File

@@ -8,6 +8,7 @@ description = "Web app for browsing, reading and downloading eBooks stored in a
authors = [{name = "@OzzieIsaacs", email = "Ozzie.Fernandez.Isaacs@googlemail.com"}] authors = [{name = "@OzzieIsaacs", email = "Ozzie.Fernandez.Isaacs@googlemail.com"}]
maintainers = [{name = "@OzzieIsaacs"}] maintainers = [{name = "@OzzieIsaacs"}]
license = "GPL-3.0-or-later" license = "GPL-3.0-or-later"
license-files = ["LICENSE"]
classifiers = [ classifiers = [
"Development Status :: 5 - Production/Stable", "Development Status :: 5 - Production/Stable",
"Programming Language :: Python :: 3", "Programming Language :: Python :: 3",
@@ -17,6 +18,7 @@ classifiers = [
"Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Operating System :: OS Independent", "Operating System :: OS Independent",
] ]
keywords = [ keywords = [
@@ -40,7 +42,7 @@ dependencies = [
"tornado>=6.4.2,<6.6", "tornado>=6.4.2,<6.6",
"Wand>=0.4.4,<0.8.0", "Wand>=0.4.4,<0.8.0",
"unidecode>=0.04.19,<1.5.0", "unidecode>=0.04.19,<1.5.0",
"lxml>=4.9.1,<5.4.0", "lxml>=4.9.1,<6.2.0",
"flask-wtf>=0.14.2,<1.3.0", "flask-wtf>=0.14.2,<1.3.0",
"chardet>=3.0.0,<5.3.0", "chardet>=3.0.0,<5.3.0",
"netifaces-plus>=0.12.0,<0.13.0", "netifaces-plus>=0.12.0,<0.13.0",
@@ -118,12 +120,10 @@ kobo = [
] ]
[project.scripts] [project.scripts]
cps = "calibreweb:main" cps = "calibreweb.__main__:main"
[tool.setuptools] [tool.setuptools]
include-package-data = true include-package-data = true
license-files = ["LICENSE"]
[tool.setuptools.dynamic] [tool.setuptools.dynamic]
version = {attr = "calibreweb.cps.constants.STABLE_VERSION"} version = {attr = "calibreweb.cps.constants.STABLE_VERSION"}

View File

@@ -12,7 +12,7 @@ SQLAlchemy>=1.3.0,<2.1.0
tornado>=6.4.2,<6.6 tornado>=6.4.2,<6.6
Wand>=0.4.4,<0.8.0 Wand>=0.4.4,<0.8.0
unidecode>=0.04.19,<1.5.0 unidecode>=0.04.19,<1.5.0
lxml>=4.9.1,<5.4.0 lxml>=4.9.1,<6.2.0
flask-wtf>=0.14.2,<1.3.0 flask-wtf>=0.14.2,<1.3.0
chardet>=3.0.0,<5.3.0 chardet>=3.0.0,<5.3.0
netifaces-plus>=0.12.0,<0.13.0 netifaces-plus>=0.12.0,<0.13.0

File diff suppressed because it is too large Load Diff