diff --git a/api/funkwhale_api/music/models.py b/api/funkwhale_api/music/models.py
index 318640c884486cd7179326213d8bc3e47ccc10f9..87f7ba8191c62547c4ebeb4c7f41a3986ef23a77 100644
--- a/api/funkwhale_api/music/models.py
+++ b/api/funkwhale_api/music/models.py
@@ -135,9 +135,9 @@ class ArtistQuerySet(models.QuerySet):
     def playable_by(self, actor, include=True):
         tracks = Track.objects.playable_by(actor, include)
         if include:
-            return self.filter(tracks__in=tracks)
+            return self.filter(tracks__in=tracks).distinct()
         else:
-            return self.exclude(tracks__in=tracks)
+            return self.exclude(tracks__in=tracks).distinct()
 
 
 class Artist(APIModelMixin):
@@ -203,9 +203,9 @@ class AlbumQuerySet(models.QuerySet):
     def playable_by(self, actor, include=True):
         tracks = Track.objects.playable_by(actor, include)
         if include:
-            return self.filter(tracks__in=tracks)
+            return self.filter(tracks__in=tracks).distinct()
         else:
-            return self.exclude(tracks__in=tracks)
+            return self.exclude(tracks__in=tracks).distinct()
 
 
 class Album(APIModelMixin):
@@ -399,9 +399,9 @@ class TrackQuerySet(models.QuerySet):
     def playable_by(self, actor, include=True):
         files = Upload.objects.playable_by(actor, include)
         if include:
-            return self.filter(uploads__in=files)
+            return self.filter(uploads__in=files).distinct()
         else:
-            return self.exclude(uploads__in=files)
+            return self.exclude(uploads__in=files).distinct()
 
     def annotate_duration(self):
         first_upload = Upload.objects.filter(track=models.OuterRef("pk")).order_by("pk")
@@ -557,8 +557,10 @@ class UploadQuerySet(models.QuerySet):
         libraries = Library.objects.viewable_by(actor)
 
         if include:
-            return self.filter(library__in=libraries, import_status="finished")
-        return self.exclude(library__in=libraries, import_status="finished")
+            return self.filter(
+                library__in=libraries, import_status="finished"
+            ).distinct()
+        return self.exclude(library__in=libraries, import_status="finished").distinct()
 
     def local(self, include=True):
         return self.exclude(library__actor__user__isnull=include)
diff --git a/api/funkwhale_api/playlists/models.py b/api/funkwhale_api/playlists/models.py
index ac86b97a00848a97718db737ed6bab1be796c02b..e1895137d3630ec9970862ce3c85bbfc0472a0ee 100644
--- a/api/funkwhale_api/playlists/models.py
+++ b/api/funkwhale_api/playlists/models.py
@@ -51,9 +51,9 @@ class PlaylistQuerySet(models.QuerySet):
     def playable_by(self, actor, include=True):
         plts = PlaylistTrack.objects.playable_by(actor, include)
         if include:
-            return self.filter(playlist_tracks__in=plts)
+            return self.filter(playlist_tracks__in=plts).distinct()
         else:
-            return self.exclude(playlist_tracks__in=plts)
+            return self.exclude(playlist_tracks__in=plts).distinct()
 
 
 class Playlist(models.Model):
@@ -167,9 +167,9 @@ class PlaylistTrackQuerySet(models.QuerySet):
     def playable_by(self, actor, include=True):
         tracks = music_models.Track.objects.playable_by(actor, include)
         if include:
-            return self.filter(track__pk__in=tracks)
+            return self.filter(track__pk__in=tracks).distinct()
         else:
-            return self.exclude(track__pk__in=tracks)
+            return self.exclude(track__pk__in=tracks).distinct()
 
 
 class PlaylistTrack(models.Model):
diff --git a/api/funkwhale_api/subsonic/renderers.py b/api/funkwhale_api/subsonic/renderers.py
index fd98633aad1e32b9316224cf4a0a3fcfec3d1e21..95b437a554b5df42245b3ccfe33b08795e33deec 100644
--- a/api/funkwhale_api/subsonic/renderers.py
+++ b/api/funkwhale_api/subsonic/renderers.py
@@ -15,7 +15,7 @@ class SubsonicJSONRenderer(renderers.JSONRenderer):
                 "status": "ok",
                 "version": "1.16.0",
                 "type": "funkwhale",
-                "funkwhale-version": funkwhale_api.__version__,
+                "funkwhaleVersion": funkwhale_api.__version__,
             }
         }
         final["subsonic-response"].update(data)
diff --git a/api/funkwhale_api/subsonic/serializers.py b/api/funkwhale_api/subsonic/serializers.py
index 35b17864153e57d0d22a521d3dbe74a24e0a1b39..023e40cac29a89168e497977543f5995dece73b5 100644
--- a/api/funkwhale_api/subsonic/serializers.py
+++ b/api/funkwhale_api/subsonic/serializers.py
@@ -226,6 +226,30 @@ def get_music_directory_data(artist):
     return data
 
 
+def get_folders(user):
+    return []
+
+
+def get_user_detail_data(user):
+    return {
+        "username": user.username,
+        "email": user.email,
+        "scrobblingEnabled": "true",
+        "adminRole": "false",
+        "settingsRole": "false",
+        "commentRole": "false",
+        "podcastRole": "false",
+        "coverArtRole": "false",
+        "shareRole": "false",
+        "uploadRole": "true",
+        "downloadRole": "true",
+        "playlistRole": "true",
+        "streamRole": "true",
+        "jukeboxRole": "true",
+        "folder": [f["id"] for f in get_folders(user)],
+    }
+
+
 class ScrobbleSerializer(serializers.Serializer):
     submission = serializers.BooleanField(default=True, required=False)
     id = serializers.PrimaryKeyRelatedField(
diff --git a/api/funkwhale_api/subsonic/views.py b/api/funkwhale_api/subsonic/views.py
index 7ca9b13a897d7e41bf0c5b42b6f865fac8c8b72d..b8cf4b4bc444c3d8f4b03f08c1cedc0e948f139c 100644
--- a/api/funkwhale_api/subsonic/views.py
+++ b/api/funkwhale_api/subsonic/views.py
@@ -8,6 +8,7 @@ from rest_framework import renderers, response, viewsets
 from rest_framework.decorators import list_route
 from rest_framework.serializers import ValidationError
 
+import funkwhale_api
 from funkwhale_api.activity import record
 from funkwhale_api.common import preferences
 from funkwhale_api.favorites.models import TrackFavorite
@@ -15,6 +16,7 @@ from funkwhale_api.music import models as music_models
 from funkwhale_api.music import utils
 from funkwhale_api.music import views as music_views
 from funkwhale_api.playlists import models as playlists_models
+from funkwhale_api.users import models as users_models
 
 from . import authentication, filters, negotiation, serializers
 
@@ -121,6 +123,8 @@ class SubsonicViewSet(viewsets.GenericViewSet):
         data = {
             "status": "ok",
             "version": "1.16.0",
+            "type": "funkwhale",
+            "funkwhaleVersion": funkwhale_api.__version__,
             "license": {
                 "valid": "true",
                 "email": "valid@valid.license",
@@ -218,6 +222,29 @@ class SubsonicViewSet(viewsets.GenericViewSet):
         data = {"starred2": {"song": serializers.get_starred_tracks_data(favorites)}}
         return response.Response(data)
 
+    @list_route(
+        methods=["get", "post"], url_name="get_random_songs", url_path="getRandomSongs"
+    )
+    def get_random_songs(self, request, *args, **kwargs):
+        data = request.GET or request.POST
+        actor = utils.get_actor_from_request(request)
+        queryset = music_models.Track.objects.all()
+        queryset = queryset.playable_by(actor)
+        try:
+            size = int(data["size"])
+        except (TypeError, KeyError, ValueError):
+            size = 50
+
+        queryset = (
+            queryset.playable_by(actor).prefetch_related("uploads").order_by("?")[:size]
+        )
+        data = {
+            "randomSongs": {
+                "song": serializers.GetSongSerializer(queryset, many=True).data
+            }
+        }
+        return response.Response(data)
+
     @list_route(methods=["get", "post"], url_name="get_starred", url_path="getStarred")
     def get_starred(self, request, *args, **kwargs):
         favorites = request.user.track_favorites.all()
@@ -426,6 +453,34 @@ class SubsonicViewSet(viewsets.GenericViewSet):
         data = {"playlist": serializers.get_playlist_detail_data(playlist)}
         return response.Response(data)
 
+    @list_route(methods=["get", "post"], url_name="get_avatar", url_path="getAvatar")
+    @find_object(
+        queryset=users_models.User.objects.exclude(avatar=None).exclude(avatar=""),
+        model_field="username__iexact",
+        field="username",
+        cast=str,
+    )
+    def get_avatar(self, request, *args, **kwargs):
+        user = kwargs.pop("obj")
+        mapping = {"nginx": "X-Accel-Redirect", "apache2": "X-Sendfile"}
+        path = music_views.get_file_path(user.avatar)
+        file_header = mapping[settings.REVERSE_PROXY_TYPE]
+        # let the proxy set the content-type
+        r = response.Response({}, content_type="")
+        r[file_header] = path
+        return r
+
+    @list_route(methods=["get", "post"], url_name="get_user", url_path="getUser")
+    @find_object(
+        queryset=lambda request: users_models.User.objects.filter(pk=request.user.pk),
+        model_field="username__iexact",
+        field="username",
+        cast=str,
+    )
+    def get_user(self, request, *args, **kwargs):
+        data = {"user": serializers.get_user_detail_data(request.user)}
+        return response.Response(data)
+
     @list_route(
         methods=["get", "post"],
         url_name="get_music_folders",
diff --git a/api/tests/subsonic/test_renderers.py b/api/tests/subsonic/test_renderers.py
index e234a993a5414915be1f7480cbd37f86d76c90bf..7e977ac45deb10d900d2127a14d5edff4980930c 100644
--- a/api/tests/subsonic/test_renderers.py
+++ b/api/tests/subsonic/test_renderers.py
@@ -13,7 +13,7 @@ def test_json_renderer():
             "status": "ok",
             "version": "1.16.0",
             "type": "funkwhale",
-            "funkwhale-version": funkwhale_api.__version__,
+            "funkwhaleVersion": funkwhale_api.__version__,
             "hello": "world",
         }
     }
diff --git a/api/tests/subsonic/test_views.py b/api/tests/subsonic/test_views.py
index f856146ec40a847e86e12889b9bab2251abbdeee..7cf5e8f120312004a1821738a60c80e400b9fc99 100644
--- a/api/tests/subsonic/test_views.py
+++ b/api/tests/subsonic/test_views.py
@@ -24,7 +24,7 @@ def test_render_content_json(db, api_client):
         "status": "ok",
         "version": "1.16.0",
         "type": "funkwhale",
-        "funkwhale-version": funkwhale_api.__version__,
+        "funkwhaleVersion": funkwhale_api.__version__,
     }
     assert response.status_code == 200
     assert json.loads(response.content) == render_json(expected)
@@ -60,6 +60,8 @@ def test_get_license(f, db, logged_in_api_client, mocker):
     expected = {
         "status": "ok",
         "version": "1.16.0",
+        "type": "funkwhale",
+        "funkwhaleVersion": funkwhale_api.__version__,
         "license": {
             "valid": "true",
             "email": "valid@valid.license",
@@ -245,6 +247,29 @@ def test_get_starred2(f, db, logged_in_api_client, factories):
     }
 
 
+@pytest.mark.parametrize("f", ["json"])
+def test_get_random_songs(f, db, logged_in_api_client, factories, mocker):
+    url = reverse("api:subsonic-get-random-songs")
+    assert url.endswith("getRandomSongs") is True
+    track1 = factories["music.Track"]()
+    track2 = factories["music.Track"]()
+    factories["music.Track"]()
+
+    order_by = mocker.patch.object(
+        music_models.TrackQuerySet, "order_by", return_value=[track1, track2]
+    )
+    response = logged_in_api_client.get(url, {"f": f, "size": 2})
+
+    assert response.status_code == 200
+    assert response.data == {
+        "randomSongs": {
+            "song": serializers.GetSongSerializer([track1, track2], many=True).data
+        }
+    }
+
+    order_by.assert_called_once_with("?")
+
+
 @pytest.mark.parametrize("f", ["xml", "json"])
 def test_get_starred(f, db, logged_in_api_client, factories):
     url = reverse("api:subsonic-get-starred")
@@ -457,6 +482,19 @@ def test_get_cover_art_album(factories, logged_in_api_client):
     ).decode("utf-8")
 
 
+def test_get_avatar(factories, logged_in_api_client):
+    user = factories["users.User"]()
+    url = reverse("api:subsonic-get-avatar")
+    assert url.endswith("getAvatar") is True
+    response = logged_in_api_client.get(url, {"username": user.username})
+
+    assert response.status_code == 200
+    assert response["Content-Type"] == ""
+    assert response["X-Accel-Redirect"] == music_views.get_file_path(
+        user.avatar
+    ).decode("utf-8")
+
+
 def test_scrobble(factories, logged_in_api_client):
     upload = factories["music.Upload"]()
     track = upload.track
@@ -468,3 +506,34 @@ def test_scrobble(factories, logged_in_api_client):
 
     listening = logged_in_api_client.user.listenings.latest("id")
     assert listening.track == track
+
+
+@pytest.mark.parametrize("f", ["json"])
+def test_get_user(f, db, logged_in_api_client, factories):
+    url = reverse("api:subsonic-get-user")
+    assert url.endswith("getUser") is True
+    response = logged_in_api_client.get(
+        url, {"f": f, "username": logged_in_api_client.user.username}
+    )
+    assert response.status_code == 200
+    assert response.data == {
+        "user": {
+            "username": logged_in_api_client.user.username,
+            "email": logged_in_api_client.user.email,
+            "scrobblingEnabled": "true",
+            "adminRole": "false",
+            "downloadRole": "true",
+            "uploadRole": "true",
+            "settingsRole": "false",
+            "playlistRole": "true",
+            "commentRole": "false",
+            "podcastRole": "false",
+            "streamRole": "true",
+            "jukeboxRole": "true",
+            "coverArtRole": "false",
+            "shareRole": "false",
+            "folder": [
+                f["id"] for f in serializers.get_folders(logged_in_api_client.user)
+            ],
+        }
+    }
diff --git a/changes/changelog.d/581.bugfix b/changes/changelog.d/581.bugfix
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9cb1cd42f9523ba50bf6656dd36d97f67fa9cecf 100644
--- a/changes/changelog.d/581.bugfix
+++ b/changes/changelog.d/581.bugfix
@@ -0,0 +1 @@
+Fixed missing track count on various library cards (#581)