62 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			62 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			Python
		
	
	
	
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")
 |