diff --git a/Dockerfile b/Dockerfile index 42644e3..c3f3446 100644 --- a/Dockerfile +++ b/Dockerfile @@ -27,11 +27,13 @@ COPY --from=requirements /usr/src/app/requirements.txt . RUN apk add --no-cache --virtual .deps \ build-base \ libjpeg-turbo-dev \ + libwebp-dev \ zlib-dev \ && pip install -r requirements.txt \ && apk del .deps \ && apk add --no-cache \ - libjpeg-turbo + libjpeg-turbo \ + libwebp COPY --from=frontend /usr/src/app/frontend/dist/ frontend/dist diff --git a/Pipfile b/Pipfile index efd2fba..aa98980 100644 --- a/Pipfile +++ b/Pipfile @@ -10,6 +10,7 @@ Flask = "*" pillow = "*" flask-cors = "*" gunicorn = "*" +flask-caching = "*" [requires] python_version = "3.7" diff --git a/Pipfile.lock b/Pipfile.lock index 033c1d4..eff3f1a 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "6bf198e4fcc5777632eb0d839a8259ef2fc737c6df23cbe2923d0d4593ab06e4" + "sha256": "92afeeaf4d754a31e04e294f6974bd9616eb0f388ce3d977ae235f3d49fa2eae" }, "pipfile-spec": 6, "requires": { @@ -25,11 +25,19 @@ }, "flask": { "hashes": [ - "sha256:a31adc27de06034c657a8dc091cc5fcb0227f2474798409bff0e9674de31a026", - "sha256:b5ae63812021cb04174fcff05d560a98387a44d9cccd4652a2bfa131ba4e4c9b" + "sha256:13f9f196f330c7c2c5d7a5cf91af894110ca0215ac051b5844701f2bfd934d52", + "sha256:45eb5a6fd193d6cf7e0cf5d8a5b31f83d5faae0293695626f539a823e93b13f6" ], "index": "pypi", - "version": "==1.1.0" + "version": "==1.1.1" + }, + "flask-caching": { + "hashes": [ + "sha256:52e236cbc836c41a5ced0c0a67b48ad180c9e2b5cb69e881089bba766db5569e", + "sha256:b0daabd5249bebfbae3da4c22987bac22047fc8b18ea2716c4fc63d57d218946" + ], + "index": "pypi", + "version": "==1.7.2" }, "flask-cors": { "hashes": [ @@ -135,10 +143,10 @@ }, "werkzeug": { "hashes": [ - "sha256:865856ebb55c4dcd0630cdd8f3331a1847a819dda7e8c750d3db6f2aa6c0209c", - "sha256:a0b915f0815982fb2a09161cb8f31708052d0951c3ba433ccc5e1aa276507ca6" + "sha256:87ae4e5b5366da2347eb3116c0e6c681a0e939a33b2805e2c0cbd282664932c4", + "sha256:a13b74dd3c45f758d4ebdb224be8f1ab8ef58b3c0ffc1783a8c7d9f4f50227e6" ], - "version": "==0.15.4" + "version": "==0.15.5" } }, "develop": {} diff --git a/backend.py b/backend.py index 1e9e625..401a93e 100644 --- a/backend.py +++ b/backend.py @@ -8,6 +8,8 @@ import werkzeug.exceptions as exceptions mimetypes['.webp'] = 'image/webp' +thumbnail_cache = {} + # https://docs.python.org/3.7/library/sqlite3.html#sqlite3.Connection.row_factory def dict_factory(cursor, row): @@ -18,12 +20,23 @@ def dict_factory(cursor, row): def generate_thumbnail(filepath): - image = Image.open(filepath) - image.thumbnail((512, 512)) - thumbnail = BytesIO() - image.save(thumbnail, format='jpeg') + if filepath in thumbnail_cache: + thumbnail = BytesIO() + thumbnail.write(thumbnail_cache[filepath]) + else: + image = Image.open(filepath) + image.thumbnail((512, 512)) + thumbnail = BytesIO() + image.save(thumbnail, 'webp') + thumbnail.seek(0) + thumbnail_cache[filepath] = thumbnail.read() + thumbnail.seek(0) - return thumbnail + + return { + 'data': thumbnail, + 'mimetype': 'image/webp' + } class CalibreDB: diff --git a/mangareader.py b/mangareader.py index 166982a..7a18512 100755 --- a/mangareader.py +++ b/mangareader.py @@ -51,7 +51,7 @@ def get_series_cover(series_id): @app.route('/api/series//cover/thumbnail') def get_series_cover_thumbnail(series_id): thumbnail = db.get_series_cover_thumbnail(series_id) - return send_file_with_etag(thumbnail, mimetype='image/jpeg') + return send_file_with_etag(thumbnail['data'], mimetype=thumbnail['mimetype']) @app.route('/api/series/') @@ -67,7 +67,7 @@ def get_volume_cover(volume_id): @app.route('/api/volume//cover/thumbnail') def get_volume_cover_thumbnail(volume_id): thumbnail = db.get_volume_cover_thumbnail(volume_id) - return send_file_with_etag(thumbnail, mimetype='image/jpeg') + return send_file_with_etag(thumbnail['data'], mimetype=thumbnail['mimetype']) @app.route('/api/volume/')