funkwhale/api/funkwhale_api/music/serializers.py

379 wiersze
10 KiB
Python
Czysty Zwykły widok Historia

from django.db import transaction
from rest_framework import serializers
from taggit.models import Tag
from versatileimagefield.serializers import VersatileImageFieldSerializer
2018-03-01 22:41:51 +00:00
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
2018-09-22 12:29:30 +00:00
from funkwhale_api.federation import routes
2018-03-01 22:41:51 +00:00
from . import filters, models, tasks
cover_field = VersatileImageFieldSerializer(allow_null=True, sizes="square")
class ArtistAlbumSerializer(serializers.ModelSerializer):
tracks_count = serializers.SerializerMethodField()
cover = cover_field
is_playable = serializers.SerializerMethodField()
class Meta:
model = models.Album
fields = (
2018-06-09 13:36:16 +00:00
"id",
"mbid",
"title",
"artist",
"release_date",
"cover",
"creation_date",
"tracks_count",
"is_playable",
)
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)
class Meta:
model = models.Artist
2018-06-09 13:36:16 +00:00
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()
2018-09-22 12:29:30 +00:00
duration = serializers.SerializerMethodField()
class Meta:
model = models.Track
fields = (
2018-06-09 13:36:16 +00:00
"id",
"mbid",
"title",
"album",
"artist",
"creation_date",
"position",
"is_playable",
"listen_url",
2018-09-22 12:29:30 +00:00
"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
2018-09-22 12:29:30 +00:00
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)
cover = cover_field
is_playable = serializers.SerializerMethodField()
class Meta:
model = models.Album
fields = (
2018-06-09 13:36:16 +00:00
"id",
"mbid",
"title",
"artist",
"tracks",
"release_date",
"cover",
"creation_date",
"is_playable",
)
def get_tracks(self, o):
ordered_tracks = sorted(
o.tracks.all(),
2018-06-09 13:36:16 +00:00
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)
cover = cover_field
class Meta:
model = models.Album
fields = (
2018-06-09 13:36:16 +00:00
"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()
2018-09-22 12:29:30 +00:00
duration = serializers.SerializerMethodField()
bitrate = serializers.SerializerMethodField()
size = serializers.SerializerMethodField()
mimetype = serializers.SerializerMethodField()
class Meta:
model = models.Track
fields = (
2018-06-09 13:36:16 +00:00
"id",
"mbid",
"title",
"album",
"artist",
"creation_date",
"position",
"lyrics",
"is_playable",
"listen_url",
2018-09-22 12:29:30 +00:00
"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
2018-09-22 12:29:30 +00:00
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):
2018-09-22 12:29:30 +00:00
uploads_count = serializers.SerializerMethodField()
size = serializers.SerializerMethodField()
class Meta:
model = models.Library
fields = [
"uuid",
"fid",
"name",
"description",
"privacy_level",
2018-09-22 12:29:30 +00:00
"uploads_count",
"size",
"creation_date",
]
read_only_fields = ["fid", "uuid", "creation_date", "actor"]
2018-09-22 12:29:30 +00:00
def get_uploads_count(self, o):
return getattr(o, "_uploads_count", o.uploads_count)
def get_size(self, o):
return getattr(o, "_size", 0)
2018-09-22 12:29:30 +00:00
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:
2018-09-22 12:29:30 +00:00
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",
]
2018-09-22 12:29:30 +00:00
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"]
2018-09-22 12:29:30 +00:00
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
2018-09-22 12:29:30 +00:00
class UploadActionSerializer(common_serializers.ActionSerializer):
actions = [
common_serializers.Action("delete", allow_all=True),
common_serializers.Action("relaunch_import", allow_all=True),
]
2018-09-22 12:29:30 +00:00
filterset_class = filters.UploadFilter
pk_field = "uuid"
@transaction.atomic
def handle_delete(self, objects):
2018-09-22 12:29:30 +00:00
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:
2018-09-22 12:29:30 +00:00
common_utils.on_commit(tasks.import_upload.delay, upload_id=pk)
class TagSerializer(serializers.ModelSerializer):
class Meta:
model = Tag
2018-06-09 13:36:16 +00:00
fields = ("id", "name", "slug")
class SimpleAlbumSerializer(serializers.ModelSerializer):
cover = cover_field
class Meta:
model = models.Album
2018-06-09 13:36:16 +00:00
fields = ("id", "mbid", "title", "release_date", "cover")
class LyricsSerializer(serializers.ModelSerializer):
class Meta:
model = models.Lyrics
2018-06-09 13:36:16 +00:00
fields = ("id", "work", "content", "content_rendered")
2018-03-01 22:41:51 +00:00
class TrackActivitySerializer(activity_serializers.ModelSerializer):
type = serializers.SerializerMethodField()
2018-06-09 13:36:16 +00:00
name = serializers.CharField(source="title")
artist = serializers.CharField(source="artist.name")
album = serializers.CharField(source="album.title")
2018-03-01 22:41:51 +00:00
class Meta:
model = models.Track
2018-06-09 13:36:16 +00:00
fields = ["id", "local_id", "name", "type", "artist", "album"]
2018-03-01 22:41:51 +00:00
def get_type(self, obj):
2018-06-09 13:36:16 +00:00
return "Audio"