diff --git a/api/funkwhale_api/musicbrainz/serializers.py b/api/funkwhale_api/musicbrainz/serializers.py index 85e1851da..787123bf4 100644 --- a/api/funkwhale_api/musicbrainz/serializers.py +++ b/api/funkwhale_api/musicbrainz/serializers.py @@ -5,6 +5,8 @@ from rest_framework import serializers from funkwhale_api import musicbrainz from funkwhale_api.tags import models as tags_models +from . import client + logger = logging.getLogger(__name__) @@ -48,7 +50,7 @@ class ArtistCreditSerializer(serializers.Serializer): return artist_credit -class ReleaseForTrackSerializer(serializers.Serializer): +class ReleaseForRecordingSerializer(serializers.Serializer): """ Serializer for Musicbrainz release data when returned in a recording object. """ @@ -74,10 +76,6 @@ class ReleaseForTrackSerializer(serializers.Serializer): album.artist_credit.set(artist_credit) album.save() tags_models.add_tags(album, *validated_data.get("tags", [])) - - if validated_data["media"]: - # an album can have various media/physical representation, we take the first one - validated_data["media"][0] return album def update(self, instance, validated_data): @@ -97,8 +95,9 @@ class RecordingSerializer(serializers.Serializer): id = serializers.CharField() title = serializers.CharField() artist_credit = ArtistCreditSerializer(many=True) - releases = ReleaseForTrackSerializer(many=True, required=False) + releases = ReleaseForRecordingSerializer(many=True, required=False) tags = serializers.ListField(child=serializers.CharField(), allow_empty=True) + position = serializers.IntegerField(required=False, allow_null=True) def create(self, validated_data): from funkwhale_api.music.models import Track @@ -109,13 +108,26 @@ class RecordingSerializer(serializers.Serializer): "mbid": validated_data["id"], # In mb a recording can have various releases, we take the fist one "album": ( - ReleaseForTrackSerializer(many=True).create(validated_data["releases"])[ - 0 - ] + ReleaseForRecordingSerializer(many=True).create( + validated_data["releases"] + )[0] if validated_data.get("releases") else None ), + # this will be none if the recording is not fetched from the release endpoint + "position": validated_data.get("position", None), } + + if defaults["album"] is not None and defaults["position"] is None: + result = client.api.releases.get( + id=validated_data["releases"][0]["id"], + includes=["tags", "artists", "recordings"], + ) + tracks = result["media"][0]["tracks"] + defaults["position"] = next( + (o for o in tracks if o["recording"]["id"] == data["mbid"]), {} + ).get("position", None) + track, created = Track.objects.get_or_create(**data, defaults=defaults) artist_credit = ArtistCreditSerializer(many=True).create( validated_data["artist_credit"] @@ -138,6 +150,8 @@ class RecordingSerializer(serializers.Serializer): class RecordingForReleaseSerializer(serializers.Serializer): id = serializers.CharField() title = serializers.CharField() + # not in Musicbrainz recording object, but used to store the position of the track in the album + position = serializers.IntegerField(required=False, allow_null=True) def create(self, validated_data): def replace_hyphens_in_keys(obj): @@ -155,6 +169,7 @@ class RecordingForReleaseSerializer(serializers.Serializer): id=validated_data["id"], includes=["tags", "artists"] ) recordings_data = replace_hyphens_in_keys(recordings_data) + recordings_data["position"] = validated_data.get("position", None) serializer = RecordingSerializer(data=recordings_data) serializer.is_valid(raise_exception=True) track = serializer.save() @@ -172,6 +187,7 @@ class RecordingForReleaseSerializer(serializers.Serializer): class TrackSerializer(serializers.Serializer): recording = RecordingForReleaseSerializer() + position = serializers.IntegerField() class MediaSerializer(serializers.Serializer): @@ -207,7 +223,12 @@ class ReleaseSerializer(serializers.Serializer): tags_models.add_tags(album, *validated_data.get("tags", [])) # an album can have various media/physical representation, we take the first one - recordings = [t["recording"] for t in validated_data["media"][0]["tracks"]] + tracks = [t for t in validated_data["media"][0]["tracks"]] + recordings = [] + for t in tracks: + t["recording"]["position"] = t["position"] + recordings.append(t["recording"]) + for r in recordings: r["album"] = album RecordingForReleaseSerializer().create(r)