Verified Commit 882e245a authored by Agate's avatar Agate 💬

Fix #1036: Favor local uploads when playing a track with multiple uploads

parent cc453edf
Pipeline #9896 passed with stages
in 5 minutes and 1 second
......@@ -281,6 +281,22 @@ def serialize_upload(upload):
}
def sort_uploads_for_listen(uploads):
"""
Given a list of uploads, return a sorted list of uploads, with local or locally
cached ones first, and older first
"""
score = {upload: 0 for upload in uploads}
for upload in uploads:
if upload.is_local:
score[upload] = 3
elif upload.audio_file:
score[upload] = 2
sorted_tuples = sorted(score.items(), key=lambda t: (t[1], -t[0].pk), reverse=True)
return [t[0] for t in sorted_tuples]
class TrackSerializer(OptionalDescriptionMixin, serializers.Serializer):
artist = serializers.SerializerMethodField()
album = TrackAlbumSerializer(read_only=True)
......@@ -310,7 +326,8 @@ class TrackSerializer(OptionalDescriptionMixin, serializers.Serializer):
return obj.listen_url
def get_uploads(self, obj):
return [serialize_upload(u) for u in getattr(obj, "playable_uploads", [])]
uploads = getattr(obj, "playable_uploads", [])
return [serialize_upload(u) for u in sort_uploads_for_listen(uploads)]
def get_tags(self, obj):
tagged_items = getattr(obj, "_prefetched_tagged_items", [])
......
......@@ -25,6 +25,7 @@ from funkwhale_api.common import (
from funkwhale_api.favorites.models import TrackFavorite
from funkwhale_api.moderation import filters as moderation_filters
from funkwhale_api.music import models as music_models
from funkwhale_api.music import serializers as music_serializers
from funkwhale_api.music import utils
from funkwhale_api.music import views as music_views
from funkwhale_api.playlists import models as playlists_models
......@@ -255,10 +256,13 @@ class SubsonicViewSet(viewsets.GenericViewSet):
data = request.GET or request.POST
track = kwargs.pop("obj")
queryset = track.uploads.select_related("track__album__artist", "track__artist")
upload = queryset.first()
if not upload:
sorted_uploads = music_serializers.sort_uploads_for_listen(queryset)
if not sorted_uploads:
return response.Response(status=404)
upload = sorted_uploads[0]
max_bitrate = data.get("maxBitRate")
try:
max_bitrate = min(max(int(max_bitrate), 0), 320) or None
......
......@@ -584,3 +584,24 @@ def test_detail_serializers_with_description_description(
expected = common_serializers.ContentSerializer(content).data
serializer = serializer_class(obj, context={"description": True})
assert serializer.data["description"] == expected
def test_sort_uploads_for_listen(factories):
local_upload = factories["music.Upload"](library__local=True)
new_local_upload = factories["music.Upload"](library__local=True)
remote_upload = factories["music.Upload"](audio_file__from_path=None)
remote_upload_with_local_version = factories["music.Upload"]()
unsorted = [
remote_upload_with_local_version,
new_local_upload,
remote_upload,
local_upload,
]
expected = [
local_upload,
new_local_upload,
remote_upload,
remote_upload_with_local_version,
]
assert serializers.sort_uploads_for_listen(unsorted) == expected
Favor local uploads when playing a track with multiple uploads (#1036)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment