diff --git a/api/funkwhale_api/subsonic/serializers.py b/api/funkwhale_api/subsonic/serializers.py index 994ad682deb4d73251ef72659b4ffd2c0f9df22f..85b969b7129ad631d8ba5cf1f270ae961288076d 100644 --- a/api/funkwhale_api/subsonic/serializers.py +++ b/api/funkwhale_api/subsonic/serializers.py @@ -5,6 +5,7 @@ from rest_framework import serializers from funkwhale_api.history import models as history_models from funkwhale_api.music import models as music_models +from funkwhale_api.music import utils as music_utils def get_artist_data(artist_values): @@ -71,7 +72,14 @@ def get_track_data(album, track, upload): "artist": album.artist.name, "track": track.position or 1, "discNumber": track.disc_number or 1, - "contentType": upload.mimetype, + # Ugly fallback to mp3 but some subsonic clients fail if the value is empty or null, and we don't always + # have the info on legacy uploads + "contentType": upload.mimetype + or ( + music_utils.get_type_from_ext(upload.extension) + if upload.extension + else "audio/mpeg" + ), "suffix": upload.extension or "", "duration": upload.duration or 0, "created": track.creation_date, diff --git a/api/tests/subsonic/test_serializers.py b/api/tests/subsonic/test_serializers.py index 2c468a4f027e20b01d975552e8a841464e2e6d4a..d6025a90b9bfc158f269a9fe0bfbab6e330ad0b4 100644 --- a/api/tests/subsonic/test_serializers.py +++ b/api/tests/subsonic/test_serializers.py @@ -1,3 +1,5 @@ +import pytest + from funkwhale_api.music import models as music_models from funkwhale_api.subsonic import serializers @@ -61,6 +63,27 @@ def test_get_artist_serializer(factories): assert serializers.GetArtistSerializer(artist).data == expected +@pytest.mark.parametrize( + "mimetype, extension, expected", + [ + ("audio/ogg", "noop", "audio/ogg"), + ("", "ogg", "audio/ogg"), + ("", "mp3", "audio/mpeg"), + ("", "", "audio/mpeg"), + ], +) +def test_get_track_data_content_type(mimetype, extension, expected, factories): + upload = factories["music.Upload"]() + upload.mimetype = mimetype + upload.audio_file = "test.{}".format(extension) + + data = serializers.get_track_data( + album=upload.track.album, track=upload.track, upload=upload + ) + + assert data["contentType"] == expected + + def test_get_album_serializer(factories): artist = factories["music.Artist"]() album = factories["music.Album"](artist=artist) diff --git a/changes/changelog.d/893.bugfix b/changes/changelog.d/893.bugfix new file mode 100644 index 0000000000000000000000000000000000000000..f37ae2a9b541fc15e5f871c0bd117ab515db2178 --- /dev/null +++ b/changes/changelog.d/893.bugfix @@ -0,0 +1 @@ +Fixed empty contentType causing client crash in some Subsonic payloads (#893)