Skip to content
Snippets Groups Projects
Commit 921317a2 authored by Eliot Berriot's avatar Eliot Berriot
Browse files

Implemented missing getSongsByGenre subsonic endpoint

parent dc731532
No related branches found
No related tags found
No related merge requests found
......@@ -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")
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment