diff --git a/api/funkwhale_api/subsonic/serializers.py b/api/funkwhale_api/subsonic/serializers.py index 237eb0cff..0048e448d 100644 --- a/api/funkwhale_api/subsonic/serializers.py +++ b/api/funkwhale_api/subsonic/serializers.py @@ -1,6 +1,8 @@ import collections from django.db.models import Count, functions +from django.db.models import Sum +from django.db.models.expressions import OuterRef, Subquery from rest_framework import serializers from funkwhale_api.history import models as history_models @@ -141,16 +143,32 @@ def get_track_data(album, track, upload): def get_album2_data(album): + # takes one upload per track + subquery = Subquery( + music_models.Upload.objects.filter(track_id=OuterRef("id")) + .order_by("id") + .values("id")[:1] + ) payload = { "id": album.id, "artistId": album.artist.id, "name": album.title, "artist": album.artist.name, "created": to_subsonic_date(album.creation_date), + "duration": album.tracks.filter(uploads__in=subquery).aggregate( + d=Sum("uploads__duration") + )["d"] + or 0, + "playCount": album.tracks.aggregate(l=Count("listenings"))["l"] or 0, } if album.attachment_cover_id: payload["coverArt"] = "al-{}".format(album.id) - + if album.tagged_items: + # exposes only first genre since the specification uses singular noun + first_genre = album.tagged_items.first() + payload["genre"] = first_genre.tag.name if first_genre else "" + if album.release_date: + payload["year"] = album.release_date.year try: payload["songCount"] = album._tracks_count except AttributeError: diff --git a/api/tests/subsonic/test_serializers.py b/api/tests/subsonic/test_serializers.py index c993942dc..75d1de895 100644 --- a/api/tests/subsonic/test_serializers.py +++ b/api/tests/subsonic/test_serializers.py @@ -1,4 +1,7 @@ import datetime + +from django.db.models.aggregates import Count, Sum +from django.db.models.expressions import OuterRef, Subquery import pytest from funkwhale_api.music import models as music_models @@ -171,7 +174,13 @@ def test_get_album_serializer(factories): album = factories["music.Album"](artist=artist, with_cover=True) track = factories["music.Track"](album=album, disc_number=42) upload = factories["music.Upload"](track=track, bitrate=42000, duration=43, size=44) - + tagged_item = factories["tags.TaggedItem"](content_object=album, tag__name="foo") + # takes one upload per track + subquery = Subquery( + music_models.Upload.objects.filter(track_id=OuterRef("id")) + .order_by("id") + .values("id")[:1] + ) expected = { "id": album.pk, "artistId": artist.pk, @@ -181,6 +190,12 @@ def test_get_album_serializer(factories): "created": serializers.to_subsonic_date(album.creation_date), "year": album.release_date.year, "coverArt": "al-{}".format(album.id), + "genre": tagged_item.tag.name, + "duration": album.tracks.filter(uploads__in=subquery).aggregate( + d=Sum("uploads__duration") + )["d"] + or 0, + "playCount": album.tracks.aggregate(l=Count("listenings"))["l"] or 0, "song": [ { "id": track.pk, diff --git a/changes/changelog.d/623.enhancement b/changes/changelog.d/623.enhancement new file mode 100644 index 000000000..be03ede12 --- /dev/null +++ b/changes/changelog.d/623.enhancement @@ -0,0 +1 @@ +Exposes more metadata in Subsonic's getAlbumList endpoint (#623)