Commit 3f82f88d authored by Luuk Scholten's avatar Luuk Scholten

Move generation of thumbnail to image path instead of templatetag

parent f4c3bbfd
...@@ -33,7 +33,7 @@ from events.feeds import DeprecationFeed ...@@ -33,7 +33,7 @@ from events.feeds import DeprecationFeed
from members.sitemaps import sitemap as members_sitemap from members.sitemaps import sitemap as members_sitemap
from partners.sitemaps import sitemap as partners_sitemap from partners.sitemaps import sitemap as partners_sitemap
from thabloid.sitemaps import sitemap as thabloid_sitemap from thabloid.sitemaps import sitemap as thabloid_sitemap
from utils.views import private_thumbnails from utils.views import private_thumbnails, generate_thumbnail
from . import views from . import views
from .sitemaps import StaticViewSitemap from .sitemaps import StaticViewSitemap
...@@ -79,6 +79,7 @@ urlpatterns = [ ...@@ -79,6 +79,7 @@ urlpatterns = [
url(r'^career/', include('partners.urls', namespace='partners')), url(r'^career/', include('partners.urls', namespace='partners')),
url(r'^contact$', TemplateView.as_view(template_name='singlepages/contact.html'), name='contact'), url(r'^contact$', TemplateView.as_view(template_name='singlepages/contact.html'), name='contact'),
url(r'^private-thumbnails/(?P<size_fit>\d+x\d+_[01])/(?P<path>.*)', private_thumbnails, name='private-thumbnails'), url(r'^private-thumbnails/(?P<size_fit>\d+x\d+_[01])/(?P<path>.*)', private_thumbnails, name='private-thumbnails'),
url(r'^generate-thumbnail/(?P<size_fit>\d+x\d+_[01])/(?P<path>[^/]+)/(?P<thumbpath>[^/]+)', generate_thumbnail, name='generate-thumbnail'),
url(r'^api/', include([ url(r'^api/', include([
url(r'^', include('events.api.urls')), url(r'^', include('events.api.urls')),
url(r'^', include('members.api.urls')), url(r'^', include('members.api.urls')),
......
...@@ -4,7 +4,7 @@ from django import template ...@@ -4,7 +4,7 @@ from django import template
from django.conf import settings from django.conf import settings
from django.db.models.fields.files import ImageFieldFile from django.db.models.fields.files import ImageFieldFile
from django.urls import reverse from django.urls import reverse
from PIL import Image, ImageOps from django.utils.http import urlquote
register = template.Library() register = template.Library()
...@@ -15,33 +15,30 @@ def thumbnail(path, size, fit=True): ...@@ -15,33 +15,30 @@ def thumbnail(path, size, fit=True):
path = path.name path = path.name
size_fit = '{}_{}'.format(size, int(fit)) size_fit = '{}_{}'.format(size, int(fit))
parts = path.split('/') parts = path.split('/')
# If we're dealing with an image in media/public/..
if parts[0] == 'public': if parts[0] == 'public':
# We actually want it to end up in media/public/thumbnails/..
# since those files can be accessed without passing through a view.
thumbpath = os.path.join(parts[0], 'thumbnails', size_fit, *parts[1:]) thumbpath = os.path.join(parts[0], 'thumbnails', size_fit, *parts[1:])
else: else:
# Otherwise simply place it in media/thumbnails.
thumbpath = os.path.join('thumbnails', size_fit, path) thumbpath = os.path.join('thumbnails', size_fit, path)
full_thumbpath = os.path.join(settings.MEDIA_ROOT, thumbpath) full_thumbpath = os.path.join(settings.MEDIA_ROOT, thumbpath)
full_path = os.path.join(settings.MEDIA_ROOT, path) full_path = os.path.join(settings.MEDIA_ROOT, path)
os.makedirs(os.path.dirname(full_thumbpath), exist_ok=True) # Check if we need to generate, then redirect to the generating route,
# otherwise just return the file path
if (not os.path.isfile(full_thumbpath) or if (not os.path.isfile(full_thumbpath) or
os.path.getmtime(full_path) > os.path.getmtime(full_thumbpath)): os.path.getmtime(full_path) > os.path.getmtime(full_thumbpath)):
image = Image.open(full_path) pathuri = urlquote(path, safe=[''])
size = tuple(int(dim) for dim in size.split('x')) thumburi = urlquote(thumbpath, safe=[''])
if not fit: return reverse('generate-thumbnail',
ratio = min([a / b for a, b in zip(size, image.size)]) args=[size_fit, pathuri, thumburi])
size = tuple(int(ratio * x) for x in image.size)
thumb = ImageOps.fit(image, size, Image.ANTIALIAS)
thumb.save(full_thumbpath)
# If we're dealing with an image in media/public/..
if parts[0] == 'public': if parts[0] == 'public':
# We actually want it to end up in media/public/thumbnails/..
# since those files can be accessed without passing through a view.
return settings.MEDIA_URL + thumbpath return settings.MEDIA_URL + thumbpath
else:
return reverse('private-thumbnails', args=[size_fit, path]) # Otherwise simply place it in media/thumbnails.
return reverse('private-thumbnails', args=[size_fit, path])
import os import os
from PIL import Image, ImageOps
from django.conf import settings from django.conf import settings
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.http import Http404 from django.http import Http404
from django.shortcuts import redirect
from django.urls import reverse
from django.utils.http import urlunquote
from sendfile import sendfile from sendfile import sendfile
from .snippets import sanitize_path from .snippets import sanitize_path
...@@ -22,3 +26,37 @@ def _private_thumbnails_unauthed(request, size_fit, path): ...@@ -22,3 +26,37 @@ def _private_thumbnails_unauthed(request, size_fit, path):
@login_required @login_required
def private_thumbnails(request, size_fit, path): def private_thumbnails(request, size_fit, path):
return _private_thumbnails_unauthed(request, size_fit, path) return _private_thumbnails_unauthed(request, size_fit, path)
def generate_thumbnail(request, size_fit, path, thumbpath):
"""The thumbnails are generated with this route. Because the
thumbnails will be generated in parallel, it will not block
page load when many thumbnails need to be generated.
After it is done, the user is redirected to the new location
of the thumbnail."""
thumbpath = urlunquote(thumbpath)
path = urlunquote(path)
full_thumbpath = os.path.join(settings.MEDIA_ROOT, thumbpath)
full_path = os.path.join(settings.MEDIA_ROOT, path)
size, fit = size_fit.split('_')
os.makedirs(os.path.dirname(full_thumbpath), exist_ok=True)
if (not os.path.isfile(full_thumbpath) or
os.path.getmtime(full_path) > os.path.getmtime(full_thumbpath)):
image = Image.open(full_path)
size = tuple(int(dim) for dim in size.split('x'))
if not fit:
ratio = min([a / b for a, b in zip(size, image.size)])
size = tuple(int(ratio * x) for x in image.size)
thumb = ImageOps.fit(image, size, Image.ANTIALIAS)
thumb.save(full_thumbpath)
# We can instantly redirect to the new correct image url
if path.split('/')[0] == 'public':
return redirect(settings.MEDIA_URL + thumbpath, permanent=True)
# Otherwise redirect to the route with an auth check
return redirect(
reverse('private-thumbnails', args=[size_fit, path]),
permanent=True
)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment