diff --git a/api/funkwhale_api/federation/serializers.py b/api/funkwhale_api/federation/serializers.py index 942892a95..6305bd073 100644 --- a/api/funkwhale_api/federation/serializers.py +++ b/api/funkwhale_api/federation/serializers.py @@ -1159,7 +1159,7 @@ class UploadSerializer(jsonld.JsonLdSerializer): "duration": instance.duration, "url": [ { - "href": utils.full_url(instance.listen_url), + "href": utils.full_url(instance.listen_url_no_download), "type": "Link", "mediaType": instance.mimetype, }, @@ -1235,7 +1235,7 @@ class ChannelUploadSerializer(serializers.Serializer): { "type": "Link", "mimeType": upload.mimetype, - "href": utils.full_url(upload.listen_url), + "href": utils.full_url(upload.listen_url_no_download), }, { "type": "Link", diff --git a/api/funkwhale_api/music/models.py b/api/funkwhale_api/music/models.py index 9f627d47c..f53e8e463 100644 --- a/api/funkwhale_api/music/models.py +++ b/api/funkwhale_api/music/models.py @@ -846,6 +846,11 @@ class Upload(models.Model): def listen_url(self): return self.track.listen_url + "?upload={}".format(self.uuid) + @property + def listen_url_no_download(self): + # Not using reverse because this is slow + return self.listen_url + "&download=false" + def get_transcoded_version(self, format, max_bitrate=None): if format: mimetype = utils.EXTENSION_TO_MIMETYPE[format] diff --git a/api/funkwhale_api/music/views.py b/api/funkwhale_api/music/views.py index 79727cd7d..57d009e99 100644 --- a/api/funkwhale_api/music/views.py +++ b/api/funkwhale_api/music/views.py @@ -393,7 +393,9 @@ def get_content_disposition(filename): return "attachment; {}".format(filename) -def handle_serve(upload, user, format=None, max_bitrate=None, proxy_media=True): +def handle_serve( + upload, user, format=None, max_bitrate=None, proxy_media=True, download=True +): f = upload # we update the accessed_date now = timezone.now() @@ -450,7 +452,8 @@ def handle_serve(upload, user, format=None, max_bitrate=None, proxy_media=True): mapping = {"nginx": "X-Accel-Redirect", "apache2": "X-Sendfile"} file_header = mapping[settings.REVERSE_PROXY_TYPE] response[file_header] = file_path - response["Content-Disposition"] = get_content_disposition(filename) + if download: + response["Content-Disposition"] = get_content_disposition(filename) if mt: response["Content-Type"] = mt @@ -476,6 +479,7 @@ class ListenViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet): "track__album__artist", "track__artist" ) explicit_file = request.GET.get("upload") + download = request.GET.get("download", "true").lower() == "true" if explicit_file: queryset = queryset.filter(uuid=explicit_file) queryset = queryset.playable_by(actor) @@ -499,6 +503,7 @@ class ListenViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet): format=format, max_bitrate=max_bitrate, proxy_media=settings.PROXY_MEDIA, + download=download, ) diff --git a/api/tests/federation/test_serializers.py b/api/tests/federation/test_serializers.py index 60898c776..4076fdd5a 100644 --- a/api/tests/federation/test_serializers.py +++ b/api/tests/federation/test_serializers.py @@ -953,7 +953,7 @@ def test_activity_pub_audio_serializer_to_ap(factories): "attributedTo": upload.library.actor.fid, "url": [ { - "href": utils.full_url(upload.listen_url), + "href": utils.full_url(upload.listen_url_no_download), "type": "Link", "mediaType": "audio/mp3", }, @@ -1105,7 +1105,7 @@ def test_channel_upload_serializer(factories): { "type": "Link", "mimeType": upload.mimetype, - "href": utils.full_url(upload.listen_url), + "href": utils.full_url(upload.listen_url_no_download), }, { "type": "Link", diff --git a/api/tests/music/test_models.py b/api/tests/music/test_models.py index c723b0104..d8022c964 100644 --- a/api/tests/music/test_models.py +++ b/api/tests/music/test_models.py @@ -437,6 +437,13 @@ def test_upload_listen_url(factories): assert upload.listen_url == expected +def test_upload_listen_url_no_download(factories): + upload = factories["music.Upload"]() + expected = upload.track.listen_url + "?upload={}&download=false".format(upload.uuid) + + assert upload.listen_url_no_download == expected + + def test_library_schedule_scan(factories, now, mocker): on_commit = mocker.patch("funkwhale_api.common.utils.on_commit") library = factories["music.Library"](uploads_count=5) diff --git a/api/tests/music/test_views.py b/api/tests/music/test_views.py index 6f962ff07..c56aeee66 100644 --- a/api/tests/music/test_views.py +++ b/api/tests/music/test_views.py @@ -382,10 +382,28 @@ def test_listen_correct_access(factories, logged_in_api_client): library__privacy_level="me", import_status="finished", ) + expected_filename = upload.track.full_name + ".ogg" url = reverse("api:v1:listen-detail", kwargs={"uuid": upload.track.uuid}) response = logged_in_api_client.get(url) assert response.status_code == 200 + assert response["Content-Disposition"] == "attachment; filename*=UTF-8''{}".format( + urllib.parse.quote(expected_filename) + ) + + +def test_listen_correct_access_download_false(factories, logged_in_api_client): + logged_in_api_client.user.create_actor() + upload = factories["music.Upload"]( + library__actor=logged_in_api_client.user.actor, + library__privacy_level="me", + import_status="finished", + ) + url = reverse("api:v1:listen-detail", kwargs={"uuid": upload.track.uuid}) + response = logged_in_api_client.get(url, {"download": "false"}) + + assert response.status_code == 200 + assert "Content-Disposition" not in response def test_listen_explicit_file(factories, logged_in_api_client, mocker, settings): @@ -406,6 +424,7 @@ def test_listen_explicit_file(factories, logged_in_api_client, mocker, settings) format=None, max_bitrate=None, proxy_media=settings.PROXY_MEDIA, + download=True, ) @@ -500,6 +519,7 @@ def test_listen_transcode(factories, now, logged_in_api_client, mocker, settings format="mp3", max_bitrate=None, proxy_media=settings.PROXY_MEDIA, + download=True, ) @@ -532,6 +552,7 @@ def test_listen_transcode_bitrate( format=None, max_bitrate=expected, proxy_media=settings.PROXY_MEDIA, + download=True, ) @@ -562,6 +583,7 @@ def test_listen_transcode_in_place( format="mp3", max_bitrate=None, proxy_media=settings.PROXY_MEDIA, + download=True, )