Use cropped covers/avatars to reduce bandwidth use
This commit is contained in:
parent
63df2e29cb
commit
979c554b4a
23 changed files with 161 additions and 39 deletions
|
|
@ -19,7 +19,7 @@ class Command(BaseCommand):
|
|||
def handle(self, *args, **options):
|
||||
name = options["script_name"]
|
||||
if not name:
|
||||
self.show_help()
|
||||
return self.show_help()
|
||||
|
||||
available_scripts = self.get_scripts()
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
from . import create_image_variations
|
||||
from . import django_permissions_to_user_permissions
|
||||
from . import test
|
||||
|
||||
|
||||
__all__ = ["create_image_variations", "django_permissions_to_user_permissions", "test"]
|
||||
30
api/funkwhale_api/common/scripts/create_image_variations.py
Normal file
30
api/funkwhale_api/common/scripts/create_image_variations.py
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
"""
|
||||
Compute different sizes of image used for Album covers and User avatars
|
||||
"""
|
||||
|
||||
from versatileimagefield.image_warmer import VersatileImageFieldWarmer
|
||||
|
||||
from funkwhale_api.music.models import Album
|
||||
from funkwhale_api.users.models import User
|
||||
|
||||
|
||||
MODELS = [(Album, "cover", "square"), (User, "avatar", "square")]
|
||||
|
||||
|
||||
def main(command, **kwargs):
|
||||
for model, attribute, key_set in MODELS:
|
||||
qs = model.objects.exclude(**{"{}__isnull".format(attribute): True})
|
||||
qs = qs.exclude(**{attribute: ""})
|
||||
warmer = VersatileImageFieldWarmer(
|
||||
instance_or_queryset=qs,
|
||||
rendition_key_set=key_set,
|
||||
image_attr=attribute,
|
||||
verbose=True,
|
||||
)
|
||||
command.stdout.write(
|
||||
"Creating images for {} / {}".format(model.__name__, attribute)
|
||||
)
|
||||
num_created, failed_to_create = warmer.warm()
|
||||
command.stdout.write(
|
||||
" {} created, {} in error".format(num_created, len(failed_to_create))
|
||||
)
|
||||
|
|
@ -18,7 +18,11 @@ class TrackFavoriteViewSet(
|
|||
):
|
||||
|
||||
serializer_class = serializers.UserTrackFavoriteSerializer
|
||||
queryset = models.TrackFavorite.objects.all()
|
||||
queryset = (
|
||||
models.TrackFavorite.objects.all()
|
||||
.select_related("track__artist", "track__album__artist", "user")
|
||||
.prefetch_related("track__files")
|
||||
)
|
||||
permission_classes = [
|
||||
permissions.ConditionalAuthentication,
|
||||
permissions.OwnerPermission,
|
||||
|
|
|
|||
|
|
@ -15,7 +15,9 @@ from django.dispatch import receiver
|
|||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from taggit.managers import TaggableManager
|
||||
|
||||
from versatileimagefield.fields import VersatileImageField
|
||||
from versatileimagefield.image_warmer import VersatileImageFieldWarmer
|
||||
|
||||
from funkwhale_api import downloader, musicbrainz
|
||||
from funkwhale_api.federation import utils as federation_utils
|
||||
|
|
@ -641,3 +643,13 @@ def update_request_status(sender, instance, created, **kwargs):
|
|||
# let's mark the request as imported since the import is over
|
||||
instance.import_request.status = "imported"
|
||||
return instance.import_request.save(update_fields=["status"])
|
||||
|
||||
|
||||
@receiver(models.signals.post_save, sender=Album)
|
||||
def warm_album_covers(sender, instance, **kwargs):
|
||||
if not instance.cover:
|
||||
return
|
||||
album_covers_warmer = VersatileImageFieldWarmer(
|
||||
instance_or_queryset=instance, rendition_key_set="square", image_attr="cover"
|
||||
)
|
||||
num_created, failed_to_create = album_covers_warmer.warm()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
from django.db.models import Q
|
||||
from rest_framework import serializers
|
||||
from taggit.models import Tag
|
||||
from versatileimagefield.serializers import VersatileImageFieldSerializer
|
||||
|
||||
from funkwhale_api.activity import serializers as activity_serializers
|
||||
from funkwhale_api.users.serializers import UserBasicSerializer
|
||||
|
|
@ -8,8 +9,12 @@ from funkwhale_api.users.serializers import UserBasicSerializer
|
|||
from . import models, tasks
|
||||
|
||||
|
||||
cover_field = VersatileImageFieldSerializer(allow_null=True, sizes="square")
|
||||
|
||||
|
||||
class ArtistAlbumSerializer(serializers.ModelSerializer):
|
||||
tracks_count = serializers.SerializerMethodField()
|
||||
cover = cover_field
|
||||
|
||||
class Meta:
|
||||
model = models.Album
|
||||
|
|
@ -87,6 +92,7 @@ class AlbumTrackSerializer(serializers.ModelSerializer):
|
|||
class AlbumSerializer(serializers.ModelSerializer):
|
||||
tracks = serializers.SerializerMethodField()
|
||||
artist = ArtistSimpleSerializer(read_only=True)
|
||||
cover = cover_field
|
||||
|
||||
class Meta:
|
||||
model = models.Album
|
||||
|
|
@ -111,6 +117,7 @@ class AlbumSerializer(serializers.ModelSerializer):
|
|||
|
||||
class TrackAlbumSerializer(serializers.ModelSerializer):
|
||||
artist = ArtistSimpleSerializer(read_only=True)
|
||||
cover = cover_field
|
||||
|
||||
class Meta:
|
||||
model = models.Album
|
||||
|
|
@ -156,6 +163,8 @@ class TagSerializer(serializers.ModelSerializer):
|
|||
|
||||
|
||||
class SimpleAlbumSerializer(serializers.ModelSerializer):
|
||||
cover = cover_field
|
||||
|
||||
class Meta:
|
||||
model = models.Album
|
||||
fields = ("id", "mbid", "title", "release_date", "cover")
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ class PlaylistSerializer(serializers.ModelSerializer):
|
|||
covers = []
|
||||
max_covers = 5
|
||||
for plt in plts:
|
||||
url = plt.track.album.cover.url
|
||||
url = plt.track.album.cover.crop["200x200"].url
|
||||
if url in covers:
|
||||
continue
|
||||
covers.append(url)
|
||||
|
|
|
|||
|
|
@ -11,12 +11,14 @@ import uuid
|
|||
from django.conf import settings
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
from django.db import models
|
||||
from django.dispatch import receiver
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from versatileimagefield.fields import VersatileImageField
|
||||
from versatileimagefield.image_warmer import VersatileImageFieldWarmer
|
||||
|
||||
from funkwhale_api.common import fields, preferences
|
||||
from funkwhale_api.common import utils as common_utils
|
||||
|
|
@ -205,3 +207,13 @@ class Invitation(models.Model):
|
|||
)
|
||||
|
||||
return super().save(**kwargs)
|
||||
|
||||
|
||||
@receiver(models.signals.post_save, sender=User)
|
||||
def warm_user_avatar(sender, instance, **kwargs):
|
||||
if not instance.avatar:
|
||||
return
|
||||
user_avatar_warmer = VersatileImageFieldWarmer(
|
||||
instance_or_queryset=instance, rendition_key_set="square", image_attr="avatar"
|
||||
)
|
||||
num_created, failed_to_create = user_avatar_warmer.warm()
|
||||
|
|
|
|||
|
|
@ -45,15 +45,7 @@ class UserActivitySerializer(activity_serializers.ModelSerializer):
|
|||
return "Person"
|
||||
|
||||
|
||||
avatar_field = VersatileImageFieldSerializer(
|
||||
allow_null=True,
|
||||
sizes=[
|
||||
("original", "url"),
|
||||
("square_crop", "crop__400x400"),
|
||||
("medium_square_crop", "crop__200x200"),
|
||||
("small_square_crop", "crop__50x50"),
|
||||
],
|
||||
)
|
||||
avatar_field = VersatileImageFieldSerializer(allow_null=True, sizes="square")
|
||||
|
||||
|
||||
class UserBasicSerializer(serializers.ModelSerializer):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue