From fd993b506353c28ff48c62d86c61efb82e7cc4f7 Mon Sep 17 00:00:00 2001 From: Oskar Manhart <52569953+oskardotglobal@users.noreply.github.com> Date: Sat, 3 Aug 2024 14:25:15 +0200 Subject: [PATCH 1/6] feat: use lazy loading for images --- cps/templates/image.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cps/templates/image.html b/cps/templates/image.html index 0bdba9a51..f84fa12b2 100644 --- a/cps/templates/image.html +++ b/cps/templates/image.html @@ -6,6 +6,7 @@ srcset="{{ srcset }}" src="{{ url_for('web.get_cover', book_id=book.id, resolution='og', c=book|last_modified) }}" alt="{{ image_alt }}" + loading="lazy" /> {%- endmacro %} @@ -16,5 +17,6 @@ srcset="{{ srcset }}" src="{{ url_for('web.get_series_cover', series_id=series.id, resolution='og', c='day'|cache_timestamp) }}" alt="{{ book_title }}" + loading="lazy" /> {%- endmacro %} From 26c8e15436ccad567c91214e92404fe6314cd065 Mon Sep 17 00:00:00 2001 From: Oskar Manhart <52569953+oskardotglobal@users.noreply.github.com> Date: Sat, 3 Aug 2024 14:59:16 +0200 Subject: [PATCH 2/6] feat: resize and convert images to webp using Flask-Image-Resizer --- cps/__init__.py | 6 +++++- cps/templates/image.html | 4 ++-- requirements.txt | 1 + 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/cps/__init__.py b/cps/__init__.py index 157dd14e5..f945b97a7 100755 --- a/cps/__init__.py +++ b/cps/__init__.py @@ -26,12 +26,13 @@ import os import mimetypes from flask import Flask +from flask_image_resizer import Images + from .MyLoginManager import MyLoginManager from flask_principal import Principal from . import logger from .cli import CliParameter -from .constants import CONFIG_DIR from .reverseproxy import ReverseProxied from .server import WebServer from .dep_check import dependency_check @@ -124,6 +125,9 @@ def create_app(): config_sql.load_configuration(ub.session, encrypt_key) config.init_config(ub.session, encrypt_key, cli_param) + # Initialize Flask-Images + Images(app) + if error: log.error(error) diff --git a/cps/templates/image.html b/cps/templates/image.html index f84fa12b2..088e6b99b 100644 --- a/cps/templates/image.html +++ b/cps/templates/image.html @@ -4,7 +4,7 @@ {% set srcset = book|get_cover_srcset %} {{ image_alt }} @@ -15,7 +15,7 @@ {% set srcset = series|get_series_srcset %} {{ book_title }} diff --git a/requirements.txt b/requirements.txt index 460a73578..965d039fa 100644 --- a/requirements.txt +++ b/requirements.txt @@ -20,3 +20,4 @@ regex>=2022.3.2,<2024.6.25 bleach>=6.0.0,<6.2.0 python-magic>=0.4.27,<0.5.0 flask-httpAuth>=4.4.0,<5.0.0 +Flask-Image-Resizer==3.0.6 From ba383643f50b2672884a465a139207513482ee05 Mon Sep 17 00:00:00 2001 From: Oskar Manhart <52569953+oskardotglobal@users.noreply.github.com> Date: Sat, 3 Aug 2024 15:49:15 +0200 Subject: [PATCH 3/6] feat: resize images directly at cover endpoint --- cps/helper.py | 30 ++++++++++++++++++++++-------- cps/templates/image.html | 4 ++-- cps/web.py | 24 ++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 10 deletions(-) diff --git a/cps/helper.py b/cps/helper.py index 004e1b0e0..37ee7bb2e 100644 --- a/cps/helper.py +++ b/cps/helper.py @@ -30,10 +30,12 @@ import requests import unidecode from uuid import uuid4 -from flask import send_from_directory, make_response, abort, url_for, Response +from flask import send_from_directory, make_response, abort, url_for, Response, redirect from flask_babel import gettext as _ from flask_babel import lazy_gettext as N_ from flask_babel import get_locale +from flask_image_resizer import resized_img_src + from .cw_login import current_user from sqlalchemy.sql.expression import true, false, and_, or_, text, func from sqlalchemy.exc import InvalidRequestError, OperationalError @@ -749,6 +751,8 @@ def get_book_cover_with_uuid(book_uuid, resolution=None): def get_book_cover_internal(book, resolution=None): + """returns an optimized version of the cover, unless using google drive""" + if book and book.has_cover: # Send the book cover thumbnail if it exists in cache @@ -757,8 +761,13 @@ def get_book_cover_internal(book, resolution=None): if thumbnail: cache = fs.FileSystem() if cache.get_cache_file_exists(thumbnail.filename, CACHE_TYPE_THUMBNAILS): - return send_from_directory(cache.get_cache_file_dir(thumbnail.filename, CACHE_TYPE_THUMBNAILS), - thumbnail.filename) + return redirect(resized_img_src( + os.path.join( + cache.get_cache_file_dir(thumbnail.filename, CACHE_TYPE_THUMBNAILS), + thumbnail.filename + ), + format="webp" + )) # Send the book cover from Google Drive if configured if config.config_use_google_drive: @@ -777,9 +786,9 @@ def get_book_cover_internal(book, resolution=None): # Send the book cover from the Calibre directory else: - cover_file_path = os.path.join(config.get_book_path(), book.path) - if os.path.isfile(os.path.join(cover_file_path, "cover.jpg")): - return send_from_directory(cover_file_path, "cover.jpg") + cover_file_path = os.path.join(config.get_book_path(), book.path, "cover.jpg") + if os.path.isfile(cover_file_path): + return redirect(resized_img_src(cover_file_path, format="webp")) else: return get_cover_on_failure() else: @@ -820,8 +829,13 @@ def get_series_cover_internal(series_id, resolution=None): if thumbnail: cache = fs.FileSystem() if cache.get_cache_file_exists(thumbnail.filename, CACHE_TYPE_THUMBNAILS): - return send_from_directory(cache.get_cache_file_dir(thumbnail.filename, CACHE_TYPE_THUMBNAILS), - thumbnail.filename) + return redirect(resized_img_src( + os.path.join( + cache.get_cache_file_dir(thumbnail.filename, CACHE_TYPE_THUMBNAILS), + thumbnail.filename + ), + format="webp" + )) return get_series_thumbnail_on_failure(series_id, resolution) diff --git a/cps/templates/image.html b/cps/templates/image.html index 088e6b99b..f84fa12b2 100644 --- a/cps/templates/image.html +++ b/cps/templates/image.html @@ -4,7 +4,7 @@ {% set srcset = book|get_cover_srcset %} {{ image_alt }} @@ -15,7 +15,7 @@ {% set srcset = series|get_series_srcset %} {{ book_title }} diff --git a/cps/web.py b/cps/web.py index 2519ebd5b..fa15b3fc3 100644 --- a/cps/web.py +++ b/cps/web.py @@ -29,6 +29,8 @@ from flask import request, redirect, send_from_directory, make_response, flash, from flask import session as flask_session from flask_babel import gettext as _ from flask_babel import get_locale +from flask_image_resizer import resized_img_src + from .cw_login import login_user, logout_user, current_user from flask_limiter import RateLimitExceeded from flask_limiter.util import get_remote_address @@ -1147,6 +1149,17 @@ def category_list(): @web.route("/cover//") @login_required_if_no_ano def get_cover(book_id, resolution=None): + return redirect( + resized_img_src( + url_for("web.get_raw_cover", book_id=book_id, resolution=resolution) + ) + ) + + +@web.route("/raw_cover/") +@web.route("/raw_cover//") +@login_required_if_no_ano +def get_raw_cover(book_id, resolution=None): resolutions = { 'og': constants.COVER_THUMBNAIL_ORIGINAL, 'sm': constants.COVER_THUMBNAIL_SMALL, @@ -1161,6 +1174,17 @@ def get_cover(book_id, resolution=None): @web.route("/series_cover//") @login_required_if_no_ano def get_series_cover(series_id, resolution=None): + return redirect( + resized_img_src( + url_for("web.get_raw_series_cover", series_id=series_id, resolution=resolution) + ) + ) + + +@web.route("/raw_series_cover/") +@web.route("/raw_series_cover//") +@login_required_if_no_ano +def get_raw_series_cover(series_id, resolution=None): resolutions = { 'og': constants.COVER_THUMBNAIL_ORIGINAL, 'sm': constants.COVER_THUMBNAIL_SMALL, From 26fb9921b20e8515199958e505356b57574ec7d9 Mon Sep 17 00:00:00 2001 From: Oskar Manhart <52569953+oskardotglobal@users.noreply.github.com> Date: Sat, 3 Aug 2024 15:49:55 +0200 Subject: [PATCH 4/6] fix: typo --- cps/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cps/__init__.py b/cps/__init__.py index f945b97a7..e6843fa0c 100644 --- a/cps/__init__.py +++ b/cps/__init__.py @@ -125,7 +125,7 @@ def create_app(): config_sql.load_configuration(ub.session, encrypt_key) config.init_config(ub.session, encrypt_key, cli_param) - # Initialize Flask-Images + # Initialize Flask-Image-Resizer Images(app) if error: From 9955e348a03331ff019b30a06cc3f61cda8e305f Mon Sep 17 00:00:00 2001 From: Oskar Manhart <52569953+oskardotglobal@users.noreply.github.com> Date: Sat, 3 Aug 2024 16:28:13 +0200 Subject: [PATCH 5/6] Revert "feat: resize images directly at cover endpoint" This reverts commit ba383643f50b2672884a465a139207513482ee05. --- cps/helper.py | 30 ++++++++---------------------- cps/templates/image.html | 4 ++-- cps/web.py | 24 ------------------------ 3 files changed, 10 insertions(+), 48 deletions(-) diff --git a/cps/helper.py b/cps/helper.py index 37ee7bb2e..004e1b0e0 100644 --- a/cps/helper.py +++ b/cps/helper.py @@ -30,12 +30,10 @@ import requests import unidecode from uuid import uuid4 -from flask import send_from_directory, make_response, abort, url_for, Response, redirect +from flask import send_from_directory, make_response, abort, url_for, Response from flask_babel import gettext as _ from flask_babel import lazy_gettext as N_ from flask_babel import get_locale -from flask_image_resizer import resized_img_src - from .cw_login import current_user from sqlalchemy.sql.expression import true, false, and_, or_, text, func from sqlalchemy.exc import InvalidRequestError, OperationalError @@ -751,8 +749,6 @@ def get_book_cover_with_uuid(book_uuid, resolution=None): def get_book_cover_internal(book, resolution=None): - """returns an optimized version of the cover, unless using google drive""" - if book and book.has_cover: # Send the book cover thumbnail if it exists in cache @@ -761,13 +757,8 @@ def get_book_cover_internal(book, resolution=None): if thumbnail: cache = fs.FileSystem() if cache.get_cache_file_exists(thumbnail.filename, CACHE_TYPE_THUMBNAILS): - return redirect(resized_img_src( - os.path.join( - cache.get_cache_file_dir(thumbnail.filename, CACHE_TYPE_THUMBNAILS), - thumbnail.filename - ), - format="webp" - )) + return send_from_directory(cache.get_cache_file_dir(thumbnail.filename, CACHE_TYPE_THUMBNAILS), + thumbnail.filename) # Send the book cover from Google Drive if configured if config.config_use_google_drive: @@ -786,9 +777,9 @@ def get_book_cover_internal(book, resolution=None): # Send the book cover from the Calibre directory else: - cover_file_path = os.path.join(config.get_book_path(), book.path, "cover.jpg") - if os.path.isfile(cover_file_path): - return redirect(resized_img_src(cover_file_path, format="webp")) + cover_file_path = os.path.join(config.get_book_path(), book.path) + if os.path.isfile(os.path.join(cover_file_path, "cover.jpg")): + return send_from_directory(cover_file_path, "cover.jpg") else: return get_cover_on_failure() else: @@ -829,13 +820,8 @@ def get_series_cover_internal(series_id, resolution=None): if thumbnail: cache = fs.FileSystem() if cache.get_cache_file_exists(thumbnail.filename, CACHE_TYPE_THUMBNAILS): - return redirect(resized_img_src( - os.path.join( - cache.get_cache_file_dir(thumbnail.filename, CACHE_TYPE_THUMBNAILS), - thumbnail.filename - ), - format="webp" - )) + return send_from_directory(cache.get_cache_file_dir(thumbnail.filename, CACHE_TYPE_THUMBNAILS), + thumbnail.filename) return get_series_thumbnail_on_failure(series_id, resolution) diff --git a/cps/templates/image.html b/cps/templates/image.html index f84fa12b2..088e6b99b 100644 --- a/cps/templates/image.html +++ b/cps/templates/image.html @@ -4,7 +4,7 @@ {% set srcset = book|get_cover_srcset %} {{ image_alt }} @@ -15,7 +15,7 @@ {% set srcset = series|get_series_srcset %} {{ book_title }} diff --git a/cps/web.py b/cps/web.py index fa15b3fc3..2519ebd5b 100644 --- a/cps/web.py +++ b/cps/web.py @@ -29,8 +29,6 @@ from flask import request, redirect, send_from_directory, make_response, flash, from flask import session as flask_session from flask_babel import gettext as _ from flask_babel import get_locale -from flask_image_resizer import resized_img_src - from .cw_login import login_user, logout_user, current_user from flask_limiter import RateLimitExceeded from flask_limiter.util import get_remote_address @@ -1149,17 +1147,6 @@ def category_list(): @web.route("/cover//") @login_required_if_no_ano def get_cover(book_id, resolution=None): - return redirect( - resized_img_src( - url_for("web.get_raw_cover", book_id=book_id, resolution=resolution) - ) - ) - - -@web.route("/raw_cover/") -@web.route("/raw_cover//") -@login_required_if_no_ano -def get_raw_cover(book_id, resolution=None): resolutions = { 'og': constants.COVER_THUMBNAIL_ORIGINAL, 'sm': constants.COVER_THUMBNAIL_SMALL, @@ -1174,17 +1161,6 @@ def get_raw_cover(book_id, resolution=None): @web.route("/series_cover//") @login_required_if_no_ano def get_series_cover(series_id, resolution=None): - return redirect( - resized_img_src( - url_for("web.get_raw_series_cover", series_id=series_id, resolution=resolution) - ) - ) - - -@web.route("/raw_series_cover/") -@web.route("/raw_series_cover//") -@login_required_if_no_ano -def get_raw_series_cover(series_id, resolution=None): resolutions = { 'og': constants.COVER_THUMBNAIL_ORIGINAL, 'sm': constants.COVER_THUMBNAIL_SMALL, From c53a5168874ea44f46abf76a1b227374111d71fa Mon Sep 17 00:00:00 2001 From: Oskar Manhart <52569953+oskardotglobal@users.noreply.github.com> Date: Mon, 5 Aug 2024 12:02:43 +0200 Subject: [PATCH 6/6] feat: revert all the resizing stuff --- cps/__init__.py | 5 ----- cps/templates/image.html | 4 ++-- requirements.txt | 1 - 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/cps/__init__.py b/cps/__init__.py index e6843fa0c..d003ed5a8 100644 --- a/cps/__init__.py +++ b/cps/__init__.py @@ -26,8 +26,6 @@ import os import mimetypes from flask import Flask -from flask_image_resizer import Images - from .MyLoginManager import MyLoginManager from flask_principal import Principal @@ -125,9 +123,6 @@ def create_app(): config_sql.load_configuration(ub.session, encrypt_key) config.init_config(ub.session, encrypt_key, cli_param) - # Initialize Flask-Image-Resizer - Images(app) - if error: log.error(error) diff --git a/cps/templates/image.html b/cps/templates/image.html index 088e6b99b..f84fa12b2 100644 --- a/cps/templates/image.html +++ b/cps/templates/image.html @@ -4,7 +4,7 @@ {% set srcset = book|get_cover_srcset %} {{ image_alt }} @@ -15,7 +15,7 @@ {% set srcset = series|get_series_srcset %} {{ book_title }} diff --git a/requirements.txt b/requirements.txt index 965d039fa..460a73578 100644 --- a/requirements.txt +++ b/requirements.txt @@ -20,4 +20,3 @@ regex>=2022.3.2,<2024.6.25 bleach>=6.0.0,<6.2.0 python-magic>=0.4.27,<0.5.0 flask-httpAuth>=4.4.0,<5.0.0 -Flask-Image-Resizer==3.0.6