Fix #1036: Favor local uploads when playing a track with multiple uploads
This commit is contained in:
parent
cc453edfec
commit
882e245a09
|
@ -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):
|
class TrackSerializer(OptionalDescriptionMixin, serializers.Serializer):
|
||||||
artist = serializers.SerializerMethodField()
|
artist = serializers.SerializerMethodField()
|
||||||
album = TrackAlbumSerializer(read_only=True)
|
album = TrackAlbumSerializer(read_only=True)
|
||||||
|
@ -310,7 +326,8 @@ class TrackSerializer(OptionalDescriptionMixin, serializers.Serializer):
|
||||||
return obj.listen_url
|
return obj.listen_url
|
||||||
|
|
||||||
def get_uploads(self, obj):
|
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):
|
def get_tags(self, obj):
|
||||||
tagged_items = getattr(obj, "_prefetched_tagged_items", [])
|
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.favorites.models import TrackFavorite
|
||||||
from funkwhale_api.moderation import filters as moderation_filters
|
from funkwhale_api.moderation import filters as moderation_filters
|
||||||
from funkwhale_api.music import models as music_models
|
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 utils
|
||||||
from funkwhale_api.music import views as music_views
|
from funkwhale_api.music import views as music_views
|
||||||
from funkwhale_api.playlists import models as playlists_models
|
from funkwhale_api.playlists import models as playlists_models
|
||||||
|
@ -255,10 +256,13 @@ class SubsonicViewSet(viewsets.GenericViewSet):
|
||||||
data = request.GET or request.POST
|
data = request.GET or request.POST
|
||||||
track = kwargs.pop("obj")
|
track = kwargs.pop("obj")
|
||||||
queryset = track.uploads.select_related("track__album__artist", "track__artist")
|
queryset = track.uploads.select_related("track__album__artist", "track__artist")
|
||||||
upload = queryset.first()
|
sorted_uploads = music_serializers.sort_uploads_for_listen(queryset)
|
||||||
if not upload:
|
|
||||||
|
if not sorted_uploads:
|
||||||
return response.Response(status=404)
|
return response.Response(status=404)
|
||||||
|
|
||||||
|
upload = sorted_uploads[0]
|
||||||
|
|
||||||
max_bitrate = data.get("maxBitRate")
|
max_bitrate = data.get("maxBitRate")
|
||||||
try:
|
try:
|
||||||
max_bitrate = min(max(int(max_bitrate), 0), 320) or None
|
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
|
expected = common_serializers.ContentSerializer(content).data
|
||||||
serializer = serializer_class(obj, context={"description": True})
|
serializer = serializer_class(obj, context={"description": True})
|
||||||
assert serializer.data["description"] == expected
|
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
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Favor local uploads when playing a track with multiple uploads (#1036)
|
Loading…
Reference in New Issue