diff --git a/README.md b/README.md index 52fa6a0c..2d6efaf5 100755 --- a/README.md +++ b/README.md @@ -107,8 +107,8 @@ Pre-built Docker images are available in the following Docker Hub repositories ( Both the Calibre-Web and Calibre-Mod images are automatically rebuilt on new releases and updates. - - Set "path to convertertool" to `/usr/bin/ebook-convert` - - Set "path to unrar" to `/usr/bin/unrar` + - Set "Path to Calibre Binaries" to `/usr/bin` + - Set "Path to Unrar" to `/usr/bin/unrar` ## Contributor Recognition diff --git a/cps/clean_html.py b/cps/clean_html.py index 907bc59e..c687f154 100644 --- a/cps/clean_html.py +++ b/cps/clean_html.py @@ -35,7 +35,7 @@ def clean_string(unsafe_text, book_id=0): try: if bleach: allowed_tags = list(ALLOWED_TAGS) - allowed_tags.extend(['p', 'span', 'div', 'pre']) + allowed_tags.extend(["p", "span", "div", "pre", "br", "h1", "h2", "h3", "h4", "h5", "h6"]) safe_text = clean_html(unsafe_text, tags=set(allowed_tags)) else: safe_text = clean_html(unsafe_text) diff --git a/cps/editbooks.py b/cps/editbooks.py index 64786c99..4a588c57 100644 --- a/cps/editbooks.py +++ b/cps/editbooks.py @@ -23,7 +23,7 @@ import os from datetime import datetime import json -from shutil import copyfile, move +from shutil import copyfile from uuid import uuid4 from markupsafe import escape, Markup # dependency of flask from functools import wraps diff --git a/cps/file_helper.py b/cps/file_helper.py index 8e2b6847..095b5ee0 100644 --- a/cps/file_helper.py +++ b/cps/file_helper.py @@ -21,17 +21,17 @@ import os import shutil import zipfile import mimetypes -import copy from io import BytesIO -try: - import magic -except ImportError: - pass from . import logger log = logger.create() +try: + import magic +except ImportError as e: + log.error("Cannot import python-magic, checking uploaded file metadata will not work: %s", e) + def get_temp_dir(): tmp_dir = os.path.join(gettempdir(), 'calibre_web') diff --git a/cps/gevent_wsgi.py b/cps/gevent_wsgi.py index cd9614c9..ab988401 100644 --- a/cps/gevent_wsgi.py +++ b/cps/gevent_wsgi.py @@ -16,7 +16,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . - +from datetime import datetime from gevent.pywsgi import WSGIHandler @@ -27,4 +27,26 @@ class MyWSGIHandler(WSGIHandler): env['RAW_URI'] = path return env + def format_request(self): + now = datetime.now().replace(microsecond=0) + length = self.response_length or '-' + if self.time_finish: + delta = '%.6f' % (self.time_finish - self.time_start) + else: + delta = '-' + forwarded = self.environ.get('HTTP_X_FORWARDED_FOR', None) + if forwarded: + client_address = forwarded + else: + client_address = self.client_address[0] if isinstance(self.client_address, tuple) else self.client_address + return '%s - - [%s] "%s" %s %s %s' % ( + client_address or '-', + now, + self.requestline or '', + # Use the native string version of the status, saved so we don't have to + # decode. But fallback to the encoded 'status' in case of subclasses + # (Is that really necessary? At least there's no overhead.) + (self._orig_status or self.status or '000').split()[0], + length, + delta) diff --git a/cps/metadata_provider/lubimyczytac.py b/cps/metadata_provider/lubimyczytac.py index 02a96992..9d4a99f8 100644 --- a/cps/metadata_provider/lubimyczytac.py +++ b/cps/metadata_provider/lubimyczytac.py @@ -137,7 +137,7 @@ class LubimyCzytac(Metadata): def _prepare_query(self, title: str) -> str: query = "" - characters_to_remove = "\?()\/" + characters_to_remove = r"\?()\/" pattern = "[" + characters_to_remove + "]" title = re.sub(pattern, "", title) title = title.replace("_", " ") diff --git a/cps/server.py b/cps/server.py index 1fdc048f..dca407a7 100644 --- a/cps/server.py +++ b/cps/server.py @@ -21,7 +21,6 @@ import os import errno import signal import socket -import asyncio try: from gevent.pywsgi import WSGIServer diff --git a/cps/tornado_wsgi.py b/cps/tornado_wsgi.py index c1571ece..f2aae6dd 100644 --- a/cps/tornado_wsgi.py +++ b/cps/tornado_wsgi.py @@ -22,6 +22,7 @@ import tornado from tornado import escape from tornado import httputil from tornado.ioloop import IOLoop +from tornado.log import access_log from typing import List, Tuple, Optional, Callable, Any, Dict, Text from types import TracebackType @@ -96,5 +97,26 @@ class MyWSGIContainer(WSGIContainer): except TypeError as e: environ = WSGIContainer.environ(request) environ['RAW_URI'] = request.path + self.env = environ return environ + def _log(self, status_code: int, request: httputil.HTTPServerRequest) -> None: + if status_code < 400: + log_method = access_log.info + elif status_code < 500: + log_method = access_log.warning + else: + log_method = access_log.error + request_time = 1000.0 * request.request_time() + assert request.method is not None + assert request.uri is not None + ip = self.env.get("HTTP_FORWARD_FOR", None) or request.remote_ip + summary = ( + request.method # type: ignore[operator] + + " " + + request.uri + + " (" + + ip + + ")" + ) + log_method("%d %s %.2fms", status_code, summary, request_time)