Source code for utils.media.services
import os
from django.db.models.fields.files import ImageFieldFile
from django.conf import settings
from django.core import signing
from django.urls import reverse
[docs]def get_thumbnail_url(path, size, fit=True):
"""
Get the thumbnail url of a media file. NEVER use this with user input.
If the thumbnail exists this function will return the url of the
media file, with signature if necessary. Does it not yet exist a route
that executes the :func:`utils.media.views.generate_thumbnail`
will be the output.
:param path: the location of the file
:param size: size of the image
:param fit: False to keep the aspect ratio, True to crop
:return: direct media url or generate-thumbnail path
"""
if isinstance(path, ImageFieldFile):
path = path.name
query = ""
size_fit = "{}_{}".format(size, int(fit))
parts = path.split("/")
sig_info = {
"size": size,
"fit": int(fit),
"path": path,
}
# Check if the image is public and assemble useful information
if parts[0] == "public":
sig_info["path"] = "/".join(parts[1:])
sig_info["visibility"] = "public"
else:
sig_info["visibility"] = "private"
sig_info["thumb_path"] = f'thumbnails/{size_fit}/{sig_info["path"]}'
url_path = f'{sig_info["visibility"]}/thumbnails/' f'{size_fit}/{sig_info["path"]}'
if sig_info["visibility"] == "public":
full_original_path = os.path.join(
settings.MEDIA_ROOT, "public", sig_info["path"]
)
full_thumb_path = os.path.join(
settings.MEDIA_ROOT, "public", sig_info["thumb_path"]
)
else:
full_original_path = os.path.join(settings.MEDIA_ROOT, sig_info["path"])
full_thumb_path = os.path.join(settings.MEDIA_ROOT, sig_info["thumb_path"])
sig_info["serve_path"] = full_thumb_path
# Check if we need to generate, then redirect to the generating route,
# otherwise just return the serving file path
if not os.path.isfile(full_thumb_path) or (
os.path.exists(full_original_path)
and os.path.getmtime(full_original_path) > os.path.getmtime(full_thumb_path)
):
# Put all image info in signature for the generate view
query = f"?sig={signing.dumps(sig_info)}"
# We provide a URL instead of calling it as a function, so that using
# it means kicking off a new GET request. If we would generate all
# thumbnails inline, loading an album overview would have high latency.
return (
reverse(
"generate-thumbnail", args=[os.path.join(size_fit, sig_info["path"])]
)
+ query
)
if sig_info["visibility"] == "private":
# Put all image info in signature for serve view
query = f"?sig={signing.dumps(sig_info)}"
return f"{settings.MEDIA_URL}{url_path}{query}"