import click from django.conf import settings from django.core.cache import cache from django.core.files.storage import default_storage from versatileimagefield import settings as vif_settings from versatileimagefield.image_warmer import VersatileImageFieldWarmer from funkwhale_api.common import utils as common_utils from funkwhale_api.common.models import Attachment from . import base @base.cli.group() def media(): """Manage media files (avatars, covers, attachments…)""" pass @media.command("generate-thumbnails") @click.option("-d", "--delete", is_flag=True) def generate_thumbnails(delete): """ Generate thumbnails for all images (avatars, covers, etc.). This can take a long time and generate a lot of I/O depending of the size of your library. """ click.echo("Deleting existing thumbnails…") if delete: try: # FileSystemStorage doesn't support deleting a non-empty directory # so we reimplemented a method to do so default_storage.force_delete("__sized__") except AttributeError: # backends doesn't support directory deletion pass MODELS = [ (Attachment, "file", "attachment_square"), ] for model, attribute, key_set in MODELS: click.echo(f"Generating thumbnails for {model._meta.label}.{attribute}…") qs = model.objects.exclude(**{f"{attribute}__isnull": True}) qs = qs.exclude(**{attribute: ""}) cache_key = "*{}{}*".format( settings.MEDIA_URL, vif_settings.VERSATILEIMAGEFIELD_SIZED_DIRNAME ) entries = cache.keys(cache_key) if entries: click.echo(f" Clearing {len(entries)} cache entries: {cache_key}…") for keys in common_utils.batch(iter(entries)): cache.delete_many(keys) warmer = VersatileImageFieldWarmer( instance_or_queryset=qs, rendition_key_set=key_set, image_attr=attribute, verbose=True, ) click.echo(" Creating images") num_created, failed_to_create = warmer.warm() click.echo(f" {num_created} created, {len(failed_to_create)} in error")