diff --git a/api/funkwhale_api/subsonic/serializers.py b/api/funkwhale_api/subsonic/serializers.py
index fc21a99f2aa540024754810d96865638d2a1eb28..5308146e14f6ffa1cc416242285e5fcf9261f14d 100644
--- a/api/funkwhale_api/subsonic/serializers.py
+++ b/api/funkwhale_api/subsonic/serializers.py
@@ -24,7 +24,8 @@ class GetArtistsSerializer(serializers.Serializer):
 
         first_letter_mapping = collections.defaultdict(list)
         for artist in values:
-            first_letter_mapping[artist["name"][0].upper()].append(artist)
+            if artist["name"]:
+                first_letter_mapping[artist["name"][0].upper()].append(artist)
 
         for letter, artists in sorted(first_letter_mapping.items()):
             letter_data = {
@@ -129,6 +130,14 @@ class GetAlbumSerializer(serializers.Serializer):
         return payload
 
 
+class GetSongSerializer(serializers.Serializer):
+    def to_representation(self, track):
+        tf = track.files.all()
+        if not len(tf):
+            return {}
+        return get_track_data(track.album, track, tf[0])
+
+
 def get_starred_tracks_data(favorites):
     by_track_id = {f.track_id: f for f in favorites}
     tracks = (
diff --git a/api/funkwhale_api/subsonic/views.py b/api/funkwhale_api/subsonic/views.py
index bb5f44166875f34ee7b625c60d93dd004d9bc6a0..b2469a8cade7aad9c27d3aa6e5aed649704477ee 100644
--- a/api/funkwhale_api/subsonic/views.py
+++ b/api/funkwhale_api/subsonic/views.py
@@ -38,7 +38,7 @@ def find_object(queryset, model_field="pk", field="id", cast=int):
                 )
             try:
                 value = cast(raw_value)
-            except (TypeError, ValidationError):
+            except (ValueError, TypeError, ValidationError):
                 return response.Response(
                     {
                         "error": {
@@ -147,6 +147,15 @@ class SubsonicViewSet(viewsets.GenericViewSet):
 
         return response.Response(payload, status=200)
 
+    @list_route(methods=["get", "post"], url_name="get_song", url_path="getSong")
+    @find_object(music_models.Track.objects.all())
+    def get_song(self, request, *args, **kwargs):
+        track = kwargs.pop("obj")
+        data = serializers.GetSongSerializer(track).data
+        payload = {"song": data}
+
+        return response.Response(payload, status=200)
+
     @list_route(
         methods=["get", "post"], url_name="get_artist_info2", url_path="getArtistInfo2"
     )
diff --git a/api/tests/subsonic/test_serializers.py b/api/tests/subsonic/test_serializers.py
index 6fdf02e2d11bd56b1d523935a1ecd4863d77b806..bd07008dfa70eda3a67867bc6dd39c27553eed91 100644
--- a/api/tests/subsonic/test_serializers.py
+++ b/api/tests/subsonic/test_serializers.py
@@ -6,6 +6,7 @@ def test_get_artists_serializer(factories):
     artist1 = factories["music.Artist"](name="eliot")
     artist2 = factories["music.Artist"](name="Ellena")
     artist3 = factories["music.Artist"](name="Rilay")
+    artist4 = factories["music.Artist"](name="")  # Shouldn't be serialised
 
     factories["music.Album"].create_batch(size=3, artist=artist1)
     factories["music.Album"].create_batch(size=2, artist=artist2)
@@ -28,7 +29,7 @@ def test_get_artists_serializer(factories):
     }
 
     queryset = artist1.__class__.objects.filter(
-        pk__in=[artist1.pk, artist2.pk, artist3.pk]
+        pk__in=[artist1.pk, artist2.pk, artist3.pk, artist4.pk]
     )
 
     assert serializers.GetArtistsSerializer(queryset).data == expected
diff --git a/api/tests/subsonic/test_views.py b/api/tests/subsonic/test_views.py
index b7431efab4a05962fa6ed5d34ba0c963336ad9a3..1c7c528ccb8f00afbbe15719b1c06dc9bfde22ac 100644
--- a/api/tests/subsonic/test_views.py
+++ b/api/tests/subsonic/test_views.py
@@ -102,6 +102,17 @@ def test_get_artist(f, db, logged_in_api_client, factories):
     assert response.data == expected
 
 
+@pytest.mark.parametrize("f", ["xml", "json"])
+def test_get_invalid_artist(f, db, logged_in_api_client, factories):
+    url = reverse("api:subsonic-get-artist")
+    assert url.endswith("getArtist") is True
+    expected = {"error": {"code": 0, "message": 'For input string "asdf"'}}
+    response = logged_in_api_client.get(url, {"id": "asdf"})
+
+    assert response.status_code == 200
+    assert response.data == expected
+
+
 @pytest.mark.parametrize("f", ["xml", "json"])
 def test_get_artist_info2(f, db, logged_in_api_client, factories):
     url = reverse("api:subsonic-get-artist-info2")
@@ -129,6 +140,20 @@ def test_get_album(f, db, logged_in_api_client, factories):
     assert response.data == expected
 
 
+@pytest.mark.parametrize("f", ["xml", "json"])
+def test_get_song(f, db, logged_in_api_client, factories):
+    url = reverse("api:subsonic-get-song")
+    assert url.endswith("getSong") is True
+    artist = factories["music.Artist"]()
+    album = factories["music.Album"](artist=artist)
+    track = factories["music.Track"](album=album)
+    tf = factories["music.TrackFile"](track=track)
+    response = logged_in_api_client.get(url, {"f": f, "id": track.pk})
+
+    assert response.status_code == 200
+    assert response.data == {"song": serializers.get_track_data(track.album, track, tf)}
+
+
 @pytest.mark.parametrize("f", ["xml", "json"])
 def test_stream(f, db, logged_in_api_client, factories, mocker):
     url = reverse("api:subsonic-stream")