diff --git a/.gitignore b/.gitignore index 97f735b..f8260f9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +cache + node_modules /frontend/dist diff --git a/Dockerfile b/Dockerfile index d08778e..e8181a2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -41,7 +41,9 @@ RUN apk add --no-cache --virtual .deps \ COPY --from=frontend /usr/src/app/frontend/dist/ frontend/dist -COPY [^frontend]* ./ +COPY *.py ./ + +VOLUME ["/usr/src/app/cache/"] ENTRYPOINT ["gunicorn", "mangareader:app", "--bind", "0.0.0.0:8000", "--chdir", "/library"] diff --git a/backend.py b/backend.py index bc5ea3b..9860bb9 100644 --- a/backend.py +++ b/backend.py @@ -1,4 +1,5 @@ from PIL import Image +from disk_cache import DiskCache from io import BytesIO from mimetypes import types_map as mimetypes from zipfile import ZipFile @@ -10,6 +11,10 @@ import werkzeug.exceptions as exceptions mimetypes['.webp'] = 'image/webp' +if os.environ.get('DISK_CACHE', '1') == '0': + disk_cache = DiskCache(enabled=False) +else: + disk_cache = DiskCache() thumbnail_cache = {} @@ -231,12 +236,18 @@ class CalibreDB: if self.webp is True and mimetype != 'image/webp': mimetype = 'image/webp' - with volume.open(page_filename) as orig_page_data: - image = Image.open(orig_page_data) - image.thumbnail((self.webp_size, self.webp_size)) - image = image.convert('RGB') - image = webp.WebPPicture.from_pil(image) - page_data = BytesIO(image.encode(self.webp_config).buffer()) + try: + page_data = disk_cache.get(f'{volume_id}-{page_number}') + except FileNotFoundError: + with volume.open(page_filename) as orig_page_data: + image = Image.open(orig_page_data) + image.thumbnail((self.webp_size, self.webp_size)) + image = image.convert('RGB') + image = webp.WebPPicture.from_pil(image) + page_data = BytesIO(image.encode(self.webp_config).buffer()) + + disk_cache.set(f'{volume_id}-{page_number}', page_data) + page_data.seek(0) else: page_data = BytesIO() page_data.write(volume.read(page_filename)) diff --git a/disk_cache.py b/disk_cache.py new file mode 100644 index 0000000..e25b1dd --- /dev/null +++ b/disk_cache.py @@ -0,0 +1,33 @@ +from io import BytesIO +import os + + +class DiskCache: + def __init__(self, path=None, enabled=True): + if path is None: + self.path = os.path.join(os.path.dirname(__file__), 'cache') + else: + self.path = path + + self.enabled = enabled + if self.enabled is False: + return + + os.makedirs(self.path, exist_ok=True) + + def set(self, identifier, buf): + if self.enabled is False: + return + + with open(self._build_path(identifier), 'wb') as f: + f.write(buf.read()) + + def get(self, identifier): + if self.enabled is False: + raise FileNotFoundError + + with open(self._build_path(identifier), 'rb') as f: + return BytesIO(f.read()) + + def _build_path(self, identifier): + return os.path.join(self.path, identifier)