diff --git a/api/funkwhale_api/music/models.py b/api/funkwhale_api/music/models.py index cf48667cc6eade81eddbc4ca2a8e8282a03b194c..5d8035f358f4dd9cdc3fbaebf6e7402f614f976e 100644 --- a/api/funkwhale_api/music/models.py +++ b/api/funkwhale_api/music/models.py @@ -22,6 +22,7 @@ from versatileimagefield.fields import VersatileImageField from funkwhale_api import downloader from funkwhale_api import musicbrainz +from funkwhale_api.federation import utils as federation_utils from . import importers from . import utils @@ -69,6 +70,12 @@ class APIModelMixin(models.Model): pass return cleaned_data + @property + def musicbrainz_url(self): + if self.mbid: + return 'https://musicbrainz.org/{}/{}'.format( + self.musicbrainz_model, self.mbid) + class Artist(APIModelMixin): name = models.CharField(max_length=255) @@ -426,6 +433,11 @@ class TrackFile(models.Model): shutil.rmtree(tmp_dir) return self.audio_file + def get_federation_url(self): + return federation_utils.full_url( + '/federation/music/file/{}'.format(self.uuid) + ) + @property def path(self): if settings.PROTECT_AUDIO_FILES: diff --git a/api/funkwhale_api/music/serializers.py b/api/funkwhale_api/music/serializers.py index 9f0b7af5c2f27b63c3477b05cf53086f62c7f7c5..5cd2f2cc218c3b1df40adff881d63b0cb6a1f21f 100644 --- a/api/funkwhale_api/music/serializers.py +++ b/api/funkwhale_api/music/serializers.py @@ -3,6 +3,8 @@ from rest_framework import serializers from taggit.models import Tag from funkwhale_api.activity import serializers as activity_serializers +from funkwhale_api.federation.serializers import AP_CONTEXT +from funkwhale_api.federation import utils as federation_utils from . import models @@ -212,6 +214,29 @@ class AudioSerializer(serializers.Serializer): metadata=metadata, ) + def to_representation(self, instance): + d = { + 'type': 'Audio', + 'id': instance.get_federation_url(), + 'name': instance.track.full_name, + 'metadata': { + 'artist': instance.track.artist.musicbrainz_url, + 'release': instance.track.album.musicbrainz_url, + 'track': instance.track.musicbrainz_url, + }, + 'url': { + 'href': federation_utils.full_url(instance.path), + 'type': 'Link', + 'mediaType': instance.mimetype + }, + 'attributedTo': [ + self.context['actor'].url + ] + } + if self.context.get('include_ap_context', True): + d['@context'] = AP_CONTEXT + return d + class AudioCollectionImportSerializer(serializers.Serializer): id = serializers.URLField() @@ -231,3 +256,24 @@ class AudioCollectionImportSerializer(serializers.Serializer): s = AudioSerializer(data=i) job = s.create(i, batch) return batch + + def to_representation(self, instance): + d = { + 'id': instance['id'], + 'actor': instance['actor'].url, + 'totalItems': len(instance['items']), + 'type': 'Collection', + 'items': [ + AudioSerializer( + i, + context={ + 'actor': instance['actor'], + 'include_ap_context': False + } + ).data + for i in instance['items'] + ] + } + if self.context.get('include_ap_context', True): + d['@context'] = AP_CONTEXT + return d diff --git a/api/tests/music/test_serializers.py b/api/tests/music/test_serializers.py index 556ac4c0e287f5031b5ede63d42dc9ebf5b85dbf..1270ae765e2e2ce52ec01732f1fb1f19641648d6 100644 --- a/api/tests/music/test_serializers.py +++ b/api/tests/music/test_serializers.py @@ -1,7 +1,10 @@ +from funkwhale_api.federation import actors +from funkwhale_api.federation import utils as federation_utils +from funkwhale_api.federation.serializers import AP_CONTEXT from funkwhale_api.music import serializers -def test_activity_pub_audio_collection_serializer(factories): +def test_activity_pub_audio_collection_serializer_to_import(factories): sender = factories['federation.Actor']() collection = { @@ -30,3 +33,62 @@ def test_activity_pub_audio_collection_serializer(factories): assert job.source == a['url']['href'] a['metadata']['mediaType'] = a['url']['mediaType'] assert job.metadata == a['metadata'] + + +def test_activity_pub_audio_serializer_to_ap(factories): + tf = factories['music.TrackFile'](mimetype='audio/mp3') + library = actors.SYSTEM_ACTORS['library'].get_actor_instance() + expected = { + '@context': AP_CONTEXT, + 'type': 'Audio', + 'id': tf.get_federation_url(), + 'name': tf.track.full_name, + 'metadata': { + 'artist': tf.track.artist.musicbrainz_url, + 'release': tf.track.album.musicbrainz_url, + 'track': tf.track.musicbrainz_url, + }, + 'url': { + 'href': federation_utils.full_url(tf.path), + 'type': 'Link', + 'mediaType': 'audio/mp3' + }, + 'attributedTo': [ + library.url + ] + } + + serializer = serializers.AudioSerializer(tf, context={'actor': library}) + + assert serializer.data == expected + + +def test_activity_pub_audio_collection_serializer_to_ap(factories): + tf1 = factories['music.TrackFile'](mimetype='audio/mp3') + tf2 = factories['music.TrackFile'](mimetype='audio/ogg') + library = actors.SYSTEM_ACTORS['library'].get_actor_instance() + expected = { + '@context': AP_CONTEXT, + 'id': 'https://test.id', + 'actor': library.url, + 'totalItems': 2, + 'type': 'Collection', + 'items': [ + serializers.AudioSerializer( + tf1, context={'actor': library, 'include_ap_context': False} + ).data, + serializers.AudioSerializer( + tf2, context={'actor': library, 'include_ap_context': False} + ).data, + ] + } + + collection = { + 'id': expected['id'], + 'actor': library, + 'items': [tf1, tf2], + } + serializer = serializers.AudioCollectionImportSerializer( + collection, context={'actor': library, 'id': 'https://test.id'}) + + assert serializer.data == expected