Cleaner handling when preview generation fails. Using original file as fallback.

This commit is contained in:
2026-01-21 23:29:51 +00:00
parent 1cb512e65d
commit 0d853032bf
+21 -13
View File
@@ -13,7 +13,7 @@ import fitz # PyMuPDF
import numpy as np import numpy as np
import pillow_heif import pillow_heif
from PIL import Image from PIL import Image
from sanic import Blueprint, empty, raw from sanic import Blueprint, empty, raw, redirect
from sanic.exceptions import NotFound from sanic.exceptions import NotFound
from sanic.log import logger from sanic.log import logger
@@ -43,12 +43,12 @@ async def preview(req, path):
maxzoom = float(req.args.get("zoom", 2.0)) maxzoom = float(req.args.get("zoom", 2.0))
quality = int(req.args.get("q", 60)) quality = int(req.args.get("q", 60))
rel = PurePosixPath(sanitize(unquote(path))) rel = PurePosixPath(sanitize(unquote(path)))
path = config.config.path / rel filepath = config.config.path / rel
stat = path.lstat() stat = filepath.lstat()
etag = config.derived_secret( etag = config.derived_secret(
"preview", rel, stat.st_mtime_ns, quality, maxsize, maxzoom "preview", rel, stat.st_mtime_ns, quality, maxsize, maxzoom
).hex() ).hex()
savename = PurePosixPath(path.name).with_suffix(".avif") savename = PurePosixPath(filepath.name).with_suffix(".avif")
headers = { headers = {
"etag": etag, "etag": etag,
"last-modified": format_date_time(stat.st_mtime), "last-modified": format_date_time(stat.st_mtime),
@@ -61,22 +61,30 @@ async def preview(req, path):
# The client has it cached, respond 304 Not Modified # The client has it cached, respond 304 Not Modified
return empty(304, headers=headers) return empty(304, headers=headers)
if not path.is_file(): if not filepath.is_file():
raise NotFound("File not found") raise NotFound("File not found")
img = await asyncio.get_event_loop().run_in_executor( img = await asyncio.get_event_loop().run_in_executor(
req.app.ctx.threadexec, dispatch, path, quality, maxsize, maxzoom req.app.ctx.threadexec, dispatch, filepath, quality, maxsize, maxzoom
) )
if not img:
# Preview generation failed, redirect to the file itself
return redirect(f"/files/{path}", status=303)
return raw(img, headers=headers) return raw(img, headers=headers)
def dispatch(path, quality, maxsize, maxzoom): def dispatch(path, quality, maxsize, maxzoom):
if path.suffix.lower() in (".pdf", ".xps", ".epub", ".mobi"): try:
return process_pdf(path, quality=quality, maxsize=maxsize, maxzoom=maxzoom) if path.suffix.lower() in (".pdf", ".xps", ".epub", ".mobi"):
type, _ = mimetypes.guess_type(path.name) return process_pdf(path, quality=quality, maxsize=maxsize, maxzoom=maxzoom)
if type and type.startswith("video/"): type, _ = mimetypes.guess_type(path.name)
return process_video(path, quality=quality, maxsize=maxsize) if type and type.startswith("video/"):
return process_image(path, quality=quality, maxsize=maxsize) return process_video(path, quality=quality, maxsize=maxsize)
return process_image(path, quality=quality, maxsize=maxsize)
except ValueError as e:
logger.warning(f"Cannot generate preview for {path.name}: {e}")
except Exception as e:
logger.exception(f"Error generating preview for {path.name}: {e}")
def process_image(path, *, maxsize, quality): def process_image(path, *, maxsize, quality):
@@ -121,7 +129,7 @@ def process_pdf(path, *, maxsize, maxzoom, quality, page_number=0):
w, h = page.rect[2:4] w, h = page.rect[2:4]
zoom = min(maxsize / w, maxsize / h, maxzoom) zoom = min(maxsize / w, maxsize / h, maxzoom)
mat = fitz.Matrix(zoom, zoom) mat = fitz.Matrix(zoom, zoom)
pix = page.get_pixmap(matrix=mat) # type: ignore[attr-defined] pix = page.get_pixmap(matrix=mat)
t_load_end = perf_counter() t_load_end = perf_counter()
t_save_start = perf_counter() t_save_start = perf_counter()