Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements to thumbnails code for using remote media storage #1952

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/settings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -716,7 +716,7 @@ Default: ``('ACCOUNTS_APPROVAL_REQUIRED', 'ACCOUNTS_VERIFICATION_REQUIRED', 'ADM
``THUMBNAILS_DIR_NAME``
-----------------------

Directory name to store thumbnails in, that will be created relative to the original image's directory.
Directory name to store thumbnails in, that will be created relative to the original image's directory, or to MEDIA_ROOT if an absolute path.

Default: ``'.thumbnails'``

Expand Down
3 changes: 2 additions & 1 deletion mezzanine/core/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,8 @@
register_setting(
name="THUMBNAILS_DIR_NAME",
description=_("Directory name to store thumbnails in, that will be "
"created relative to the original image's directory."),
"created relative to the original image's directory, or to "
"MEDIA_ROOT if an absolute path."),
editable=False,
default=".thumbnails",
)
Expand Down
58 changes: 35 additions & 23 deletions mezzanine/core/templatetags/mezzanine_tags.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
from __future__ import absolute_import, division, unicode_literals
from future.builtins import int, open, str

import sys

from django.core.files.uploadedfile import InMemoryUploadedFile
from future.builtins import int, str

from hashlib import md5
import os

from six import BytesIO

try:
from urllib.parse import quote, unquote
except ImportError:
Expand All @@ -13,7 +20,6 @@
from django.contrib.auth import REDIRECT_FIELD_NAME
from django.contrib.sites.models import Site
from django.core.exceptions import ObjectDoesNotExist
from django.core.files import File
from django.core.files.storage import default_storage
from django.urls import reverse, resolve, NoReverseMatch
from django.db.models import Model
Expand Down Expand Up @@ -312,24 +318,29 @@ def thumbnail(image_url, width, height, upscale=True, quality=95, left=.5,
# image, which is something we do in filebrowser when a new image
# is written, allowing us to purge any previously generated
# thumbnails that may match a new image name.
thumb_dir = os.path.join(settings.MEDIA_ROOT, image_dir,
settings.THUMBNAILS_DIR_NAME, image_name)
if not os.path.exists(thumb_dir):
try:
os.makedirs(thumb_dir)
except OSError:
pass
if os.path.isabs(settings.THUMBNAILS_DIR_NAME):
thumb_dir = os.path.join(settings.MEDIA_ROOT,
settings.THUMBNAILS_DIR_NAME,
image_dir, image_name)
thumb_url = ("%s/%s/%s/%s" % (settings.THUMBNAILS_DIR_NAME,
os.path.dirname(image_url),
quote(image_name.encode("utf-8")),
quote(thumb_name.encode("utf-8")))
).lstrip('/')
else:
thumb_dir = os.path.join(settings.MEDIA_ROOT, image_dir,
settings.THUMBNAILS_DIR_NAME, image_name)
thumb_url = "%s/%s/%s" % (settings.THUMBNAILS_DIR_NAME,
quote(image_name.encode("utf-8")),
quote(thumb_name.encode("utf-8")))
image_url_path = os.path.dirname(image_url)
if image_url_path:
thumb_url = "%s/%s" % (image_url_path, thumb_url)

thumb_path = os.path.join(thumb_dir, thumb_name)
thumb_url = "%s/%s/%s" % (settings.THUMBNAILS_DIR_NAME,
quote(image_name.encode("utf-8")),
quote(thumb_name.encode("utf-8")))
image_url_path = os.path.dirname(image_url)
if image_url_path:
thumb_url = "%s/%s" % (image_url_path, thumb_url)

try:
thumb_exists = os.path.exists(thumb_path)
thumb_exists = default_storage.exists(thumb_url)
except UnicodeEncodeError:
# The image that was saved to a filesystem with utf-8 support,
# but somehow the locale has changed and the filesystem does not
Expand Down Expand Up @@ -422,18 +433,19 @@ def thumbnail(image_url, width, height, upscale=True, quality=95, left=.5,
to_pos = (left, top)
try:
image = ImageOps.fit(image, to_size, Image.ANTIALIAS, 0, to_pos)
image = image.save(thumb_path, filetype, quality=quality, **image_info)
# Push a remote copy of the thumbnail if MEDIA_URL is
# absolute.
if "://" in settings.MEDIA_URL:
with open(thumb_path, "rb") as f:
default_storage.save(unquote(thumb_url), File(f))
thumb_io = BytesIO()
image.save(thumb_io, filetype, quality=quality, **image_info)
thumb_file = InMemoryUploadedFile(
thumb_io, None, 'foo.jpg', 'image/jpg',
sys.getsizeof(thumb_io), None
)
default_storage.save(unquote(thumb_url), thumb_file)
except Exception:
# If an error occurred, a corrupted image may have been saved,
# so remove it, otherwise the check for it existing will just
# return the corrupted image next time it's requested.
try:
os.remove(thumb_path)
default_storage.delete(thumb_path)
except Exception:
pass
return image_url
Expand Down