diff --git a/api/funkwhale_api/playlists/models.py b/api/funkwhale_api/playlists/models.py index b227a545d..cef84ad25 100644 --- a/api/funkwhale_api/playlists/models.py +++ b/api/funkwhale_api/playlists/models.py @@ -1,4 +1,6 @@ from django.db import models, transaction +from django.db.models.expressions import OuterRef, Subquery +from django.db.models import Q from django.utils import timezone from rest_framework import exceptions @@ -11,8 +13,18 @@ class PlaylistQuerySet(models.QuerySet): return self.annotate(_tracks_count=models.Count("playlist_tracks")) def with_duration(self): + subquery = Subquery( + music_models.Upload.objects.filter( + track_id=OuterRef("playlist_tracks__track__id") + ) + .order_by("id") + .values("id")[:1] + ) return self.annotate( - duration=models.Sum("playlist_tracks__track__uploads__duration") + duration=models.Sum( + "playlist_tracks__track__uploads__duration", + filter=Q(playlist_tracks__track__uploads=subquery), + ) ) def with_covers(self): diff --git a/api/tests/playlists/test_serializers.py b/api/tests/playlists/test_serializers.py index b1cae0f36..15624b9f2 100644 --- a/api/tests/playlists/test_serializers.py +++ b/api/tests/playlists/test_serializers.py @@ -29,15 +29,46 @@ def test_playlist_serializer_include_covers(factories, api_request): assert serializer.data["album_covers"] == expected -def test_playlist_serializer_include_duration(factories, api_request): +def test_playlist_serializer_include_duration(tmpfile, factories): playlist = factories["playlists.Playlist"]() - upload1 = factories["music.Upload"](duration=15) - upload2 = factories["music.Upload"](duration=30) - playlist.insert_many([upload1.track, upload2.track]) + event = { + "path": tmpfile.name, + } + library = factories["music.Library"]() + track1 = factories["music.Track"]() + track2 = factories["music.Track"]() + factories["music.Upload"]( + source="file://{}".format(event["path"]), + track=track1, + checksum="old", + library=library, + import_status="finished", + audio_file=None, + duration=21, + ) + factories["music.Upload"]( + source="file://{}".format(event["path"]), + track=track1, + checksum="old", + library=library, + import_status="finished", + audio_file=None, + duration=21, + ) + factories["music.Upload"]( + source="file://{}".format(event["path"]), + track=track2, + checksum="old", + library=library, + import_status="finished", + audio_file=None, + duration=21, + ) + playlist.insert_many([track1, track2]) qs = playlist.__class__.objects.with_duration().with_tracks_count() serializer = serializers.PlaylistSerializer(qs.get()) - assert serializer.data["duration"] == 45 + assert serializer.data["duration"] == 42 def test_playlist_serializer(factories, to_api_date):