kopia lustrzana https://dev.funkwhale.audio/funkwhale/funkwhale
Merge branch 'subsonic-getsongsbygenre' into 'develop'
Implemented missing getSongsByGenre subsonic endpoint See merge request funkwhale/funkwhale!897environments/review-front-927-m6zslj/deployments/2768
commit
955f88e976
|
@ -108,7 +108,6 @@ class TrackFactory(
|
|||
title = factory.Faker("sentence", nb_words=3)
|
||||
mbid = factory.Faker("uuid4")
|
||||
album = factory.SubFactory(AlbumFactory)
|
||||
artist = factory.SelfAttribute("album.artist")
|
||||
position = 1
|
||||
playable = playable_factory("track")
|
||||
|
||||
|
@ -124,6 +123,26 @@ class TrackFactory(
|
|||
fid=factory.Faker("federation_url", local=True), album__local=True
|
||||
)
|
||||
|
||||
@factory.post_generation
|
||||
def artist(self, created, extracted, **kwargs):
|
||||
"""
|
||||
A bit intricated, because we want to be able to specify a different
|
||||
track artist with a fallback on album artist if nothing is specified.
|
||||
|
||||
And handle cases where build or build_batch are used (so no db calls)
|
||||
"""
|
||||
if extracted:
|
||||
self.artist = extracted
|
||||
elif kwargs:
|
||||
if created:
|
||||
self.artist = ArtistFactory(**kwargs)
|
||||
else:
|
||||
self.artist = ArtistFactory.build(**kwargs)
|
||||
elif self.album:
|
||||
self.artist = self.album.artist
|
||||
if created:
|
||||
self.save()
|
||||
|
||||
@factory.post_generation
|
||||
def license(self, created, extracted, **kwargs):
|
||||
if not created:
|
||||
|
|
|
@ -333,6 +333,48 @@ class SubsonicViewSet(viewsets.GenericViewSet):
|
|||
}
|
||||
return response.Response(data)
|
||||
|
||||
@action(
|
||||
detail=False,
|
||||
methods=["get", "post"],
|
||||
url_name="get_songs_by_genre",
|
||||
url_path="getSongsByGenre",
|
||||
)
|
||||
def get_songs_by_genre(self, request, *args, **kwargs):
|
||||
data = request.GET or request.POST
|
||||
actor = utils.get_actor_from_request(request)
|
||||
queryset = music_models.Track.objects.all().exclude(
|
||||
moderation_filters.get_filtered_content_query(
|
||||
moderation_filters.USER_FILTER_CONFIG["TRACK"], request.user
|
||||
)
|
||||
)
|
||||
queryset = queryset.playable_by(actor)
|
||||
try:
|
||||
size = int(
|
||||
data["count"]
|
||||
) # yep. Some endpoints have size, other have count…
|
||||
except (TypeError, KeyError, ValueError):
|
||||
size = 50
|
||||
|
||||
genre = data.get("genre")
|
||||
queryset = (
|
||||
queryset.playable_by(actor)
|
||||
.filter(
|
||||
Q(tagged_items__tag__name=genre)
|
||||
| Q(artist__tagged_items__tag__name=genre)
|
||||
| Q(album__artist__tagged_items__tag__name=genre)
|
||||
| Q(album__tagged_items__tag__name=genre)
|
||||
)
|
||||
.prefetch_related("uploads")
|
||||
.distinct()
|
||||
.order_by("-creation_date")[:size]
|
||||
)
|
||||
data = {
|
||||
"songsByGenre": {
|
||||
"song": serializers.GetSongSerializer(queryset, many=True).data
|
||||
}
|
||||
}
|
||||
return response.Response(data)
|
||||
|
||||
@action(
|
||||
detail=False,
|
||||
methods=["get", "post"],
|
||||
|
|
|
@ -469,6 +469,28 @@ def test_get_album_list2_by_genre(f, db, logged_in_api_client, factories):
|
|||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize("f", ["json"])
|
||||
@pytest.mark.parametrize(
|
||||
"tags_field",
|
||||
["set_tags", "artist__set_tags", "album__set_tags", "album__artist__set_tags"],
|
||||
)
|
||||
def test_get_songs_by_genre(f, tags_field, db, logged_in_api_client, factories):
|
||||
url = reverse("api:subsonic-get_songs_by_genre")
|
||||
assert url.endswith("getSongsByGenre") is True
|
||||
track1 = factories["music.Track"](playable=True, **{tags_field: ["Rock"]})
|
||||
track2 = factories["music.Track"](playable=True, **{tags_field: ["Rock"]})
|
||||
factories["music.Track"](playable=True, **{tags_field: ["Pop"]})
|
||||
expected = {
|
||||
"songsByGenre": {"song": serializers.get_song_list_data([track2, track1])}
|
||||
}
|
||||
|
||||
response = logged_in_api_client.get(
|
||||
url, {"f": f, "count": 5, "offset": 0, "genre": "rock"}
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert response.data == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize("f", ["json"])
|
||||
def test_search3(f, db, logged_in_api_client, factories):
|
||||
url = reverse("api:subsonic-search3")
|
||||
|
|
Ładowanie…
Reference in New Issue