Skip to content
Snippets Groups Projects
serializers.py 10.3 KiB
Newer Older
  • Learn to ignore specific revisions
  • from django.db import transaction
    
    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.common import serializers as common_serializers
    from funkwhale_api.common import utils as common_utils
    
    Eliot Berriot's avatar
    Eliot Berriot committed
    from funkwhale_api.federation import routes
    
    from . import filters, models, tasks
    
    cover_field = VersatileImageFieldSerializer(allow_null=True, sizes="square")
    
    
    
    class ArtistAlbumSerializer(serializers.ModelSerializer):
        tracks_count = serializers.SerializerMethodField()
    
        is_playable = serializers.SerializerMethodField()
    
            model = models.Album
            fields = (
    
    Eliot Berriot's avatar
    Eliot Berriot committed
                "id",
                "mbid",
                "title",
                "artist",
                "release_date",
                "cover",
                "creation_date",
                "tracks_count",
    
        def get_tracks_count(self, o):
            return o._tracks_count
    
        def get_is_playable(self, obj):
            try:
                return bool(obj.is_playable_by_actor)
            except AttributeError:
                return None
    
    
    
    class ArtistWithAlbumsSerializer(serializers.ModelSerializer):
        albums = ArtistAlbumSerializer(many=True, read_only=True)
    
    Eliot Berriot's avatar
    Eliot Berriot committed
            fields = ("id", "mbid", "name", "creation_date", "albums")
    
    class ArtistSimpleSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Artist
            fields = ("id", "mbid", "name", "creation_date")
    
    
    
    class AlbumTrackSerializer(serializers.ModelSerializer):
    
        artist = ArtistSimpleSerializer(read_only=True)
    
        is_playable = serializers.SerializerMethodField()
        listen_url = serializers.SerializerMethodField()
    
    Eliot Berriot's avatar
    Eliot Berriot committed
        duration = serializers.SerializerMethodField()
    
            model = models.Track
            fields = (
    
    Eliot Berriot's avatar
    Eliot Berriot committed
                "id",
                "mbid",
                "title",
                "album",
                "artist",
                "creation_date",
                "position",
    
                "is_playable",
                "listen_url",
    
    Eliot Berriot's avatar
    Eliot Berriot committed
                "duration",
    
        def get_is_playable(self, obj):
            try:
                return bool(obj.is_playable_by_actor)
            except AttributeError:
                return None
    
        def get_listen_url(self, obj):
            return obj.listen_url
    
    
    Eliot Berriot's avatar
    Eliot Berriot committed
        def get_duration(self, obj):
            try:
                return obj.duration
            except AttributeError:
                return None
    
    
    class AlbumSerializer(serializers.ModelSerializer):
    
        tracks = serializers.SerializerMethodField()
        artist = ArtistSimpleSerializer(read_only=True)
    
        is_playable = serializers.SerializerMethodField()
    
    Eliot Berriot's avatar
    Eliot Berriot committed
                "id",
                "mbid",
                "title",
                "artist",
                "tracks",
                "release_date",
                "cover",
                "creation_date",
    
        def get_tracks(self, o):
    
            ordered_tracks = sorted(
                o.tracks.all(),
    
    Eliot Berriot's avatar
    Eliot Berriot committed
                key=lambda v: (v.position, v.title) if v.position else (99999, v.title),
    
            return AlbumTrackSerializer(ordered_tracks, many=True).data
    
        def get_is_playable(self, obj):
            try:
                return any([bool(t.is_playable_by_actor) for t in obj.tracks.all()])
            except AttributeError:
                return None
    
    
    class TrackAlbumSerializer(serializers.ModelSerializer):
        artist = ArtistSimpleSerializer(read_only=True)
    
    Eliot Berriot's avatar
    Eliot Berriot committed
                "id",
                "mbid",
                "title",
                "artist",
                "release_date",
                "cover",
                "creation_date",
    
    class TrackSerializer(serializers.ModelSerializer):
        artist = ArtistSimpleSerializer(read_only=True)
        album = TrackAlbumSerializer(read_only=True)
        lyrics = serializers.SerializerMethodField()
    
        is_playable = serializers.SerializerMethodField()
        listen_url = serializers.SerializerMethodField()
    
    Eliot Berriot's avatar
    Eliot Berriot committed
        duration = serializers.SerializerMethodField()
        bitrate = serializers.SerializerMethodField()
        size = serializers.SerializerMethodField()
        mimetype = serializers.SerializerMethodField()
    
    Eliot Berriot's avatar
    Eliot Berriot committed
                "id",
                "mbid",
                "title",
                "album",
                "artist",
                "creation_date",
                "position",
                "lyrics",
    
                "is_playable",
                "listen_url",
    
    Eliot Berriot's avatar
    Eliot Berriot committed
                "duration",
                "bitrate",
                "size",
                "mimetype",
    
        def get_lyrics(self, obj):
            return obj.get_lyrics_url()
    
        def get_listen_url(self, obj):
            return obj.listen_url
    
        def get_is_playable(self, obj):
            try:
                return bool(obj.is_playable_by_actor)
            except AttributeError:
                return None
    
    
    Eliot Berriot's avatar
    Eliot Berriot committed
        def get_duration(self, obj):
            try:
                return obj.duration
            except AttributeError:
                return None
    
        def get_bitrate(self, obj):
            try:
                return obj.bitrate
            except AttributeError:
                return None
    
        def get_size(self, obj):
            try:
                return obj.size
            except AttributeError:
                return None
    
        def get_mimetype(self, obj):
            try:
                return obj.mimetype
            except AttributeError:
                return None
    
    
    
    class LibraryForOwnerSerializer(serializers.ModelSerializer):
    
    Eliot Berriot's avatar
    Eliot Berriot committed
        uploads_count = serializers.SerializerMethodField()
    
        size = serializers.SerializerMethodField()
    
        class Meta:
            model = models.Library
            fields = [
                "uuid",
                "fid",
                "name",
                "description",
                "privacy_level",
    
    Eliot Berriot's avatar
    Eliot Berriot committed
                "uploads_count",
    
                "size",
                "creation_date",
            ]
            read_only_fields = ["fid", "uuid", "creation_date", "actor"]
    
    
    Eliot Berriot's avatar
    Eliot Berriot committed
        def get_uploads_count(self, o):
            return getattr(o, "_uploads_count", o.uploads_count)
    
    
        def get_size(self, o):
            return getattr(o, "_size", 0)
    
    
    
    Eliot Berriot's avatar
    Eliot Berriot committed
    class UploadSerializer(serializers.ModelSerializer):
    
        track = TrackSerializer(required=False, allow_null=True)
        library = common_serializers.RelatedField(
            "uuid",
            LibraryForOwnerSerializer(),
            required=True,
            filters=lambda context: {"actor": context["user"].actor},
        )
    
        class Meta:
    
    Eliot Berriot's avatar
    Eliot Berriot committed
            model = models.Upload
    
            fields = [
                "uuid",
                "filename",
                "creation_date",
                "mimetype",
                "track",
                "library",
                "duration",
                "mimetype",
                "bitrate",
                "size",
                "import_date",
                "import_status",
            ]
    
            read_only_fields = [
                "uuid",
                "creation_date",
                "duration",
                "mimetype",
                "bitrate",
                "size",
                "track",
                "import_date",
                "import_status",
            ]
    
    
    
    Eliot Berriot's avatar
    Eliot Berriot committed
    class UploadForOwnerSerializer(UploadSerializer):
        class Meta(UploadSerializer.Meta):
            fields = UploadSerializer.Meta.fields + [
    
                "import_details",
                "import_metadata",
                "import_reference",
                "metadata",
                "source",
                "audio_file",
            ]
            write_only_fields = ["audio_file"]
    
    Eliot Berriot's avatar
    Eliot Berriot committed
            read_only_fields = UploadSerializer.Meta.read_only_fields + [
    
                "import_details",
                "import_metadata",
                "metadata",
            ]
    
        def to_representation(self, obj):
            r = super().to_representation(obj)
            if "audio_file" in r:
                del r["audio_file"]
            return r
    
        def validate(self, validated_data):
            if "audio_file" in validated_data:
                self.validate_upload_quota(validated_data["audio_file"])
    
            return super().validate(validated_data)
    
        def validate_upload_quota(self, f):
            quota_status = self.context["user"].get_quota_status()
            if (f.size / 1000 / 1000) > quota_status["remaining"]:
                raise serializers.ValidationError("upload_quota_reached")
    
            return f
    
    
    
    Eliot Berriot's avatar
    Eliot Berriot committed
    class UploadActionSerializer(common_serializers.ActionSerializer):
    
        actions = [
            common_serializers.Action("delete", allow_all=True),
            common_serializers.Action("relaunch_import", allow_all=True),
        ]
    
    Eliot Berriot's avatar
    Eliot Berriot committed
        filterset_class = filters.UploadFilter
    
        pk_field = "uuid"
    
        @transaction.atomic
        def handle_delete(self, objects):
    
    Eliot Berriot's avatar
    Eliot Berriot committed
            libraries = sorted(set(objects.values_list("library", flat=True)))
            for id in libraries:
                # we group deletes by library for easier federation
                uploads = objects.filter(library__pk=id).select_related("library__actor")
                for chunk in common_utils.chunk_queryset(uploads, 100):
                    routes.outbox.dispatch(
                        {"type": "Delete", "object": {"type": "Audio"}},
                        context={"uploads": chunk},
                    )
    
    
            return objects.delete()
    
        @transaction.atomic
        def handle_relaunch_import(self, objects):
            qs = objects.exclude(import_status="finished")
            pks = list(qs.values_list("id", flat=True))
            qs.update(import_status="pending")
            for pk in pks:
    
                common_utils.on_commit(tasks.process_upload.delay, upload_id=pk)
    
    class TagSerializer(serializers.ModelSerializer):
    
    Eliot Berriot's avatar
    Eliot Berriot committed
            fields = ("id", "name", "slug")
    
    class SimpleAlbumSerializer(serializers.ModelSerializer):
    
    Eliot Berriot's avatar
    Eliot Berriot committed
            fields = ("id", "mbid", "title", "release_date", "cover")
    
    
    
    class LyricsSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Lyrics
    
    Eliot Berriot's avatar
    Eliot Berriot committed
            fields = ("id", "work", "content", "content_rendered")
    
    class TrackActivitySerializer(activity_serializers.ModelSerializer):
        type = serializers.SerializerMethodField()
    
    Eliot Berriot's avatar
    Eliot Berriot committed
        name = serializers.CharField(source="title")
        artist = serializers.CharField(source="artist.name")
        album = serializers.CharField(source="album.title")
    
    
        class Meta:
            model = models.Track
    
    Eliot Berriot's avatar
    Eliot Berriot committed
            fields = ["id", "local_id", "name", "type", "artist", "album"]
    
    
        def get_type(self, obj):
    
    Eliot Berriot's avatar
    Eliot Berriot committed
            return "Audio"