Implemented missing getSongsByGenre subsonic endpoint
This commit is contained in:
parent
dc731532b9
commit
921317a217
|
@ -108,7 +108,6 @@ class TrackFactory(
|
||||||
title = factory.Faker("sentence", nb_words=3)
|
title = factory.Faker("sentence", nb_words=3)
|
||||||
mbid = factory.Faker("uuid4")
|
mbid = factory.Faker("uuid4")
|
||||||
album = factory.SubFactory(AlbumFactory)
|
album = factory.SubFactory(AlbumFactory)
|
||||||
artist = factory.SelfAttribute("album.artist")
|
|
||||||
position = 1
|
position = 1
|
||||||
playable = playable_factory("track")
|
playable = playable_factory("track")
|
||||||
|
|
||||||
|
@ -124,6 +123,26 @@ class TrackFactory(
|
||||||
fid=factory.Faker("federation_url", local=True), album__local=True
|
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
|
@factory.post_generation
|
||||||
def license(self, created, extracted, **kwargs):
|
def license(self, created, extracted, **kwargs):
|
||||||
if not created:
|
if not created:
|
||||||
|
|
|
@ -333,6 +333,48 @@ class SubsonicViewSet(viewsets.GenericViewSet):
|
||||||
}
|
}
|
||||||
return response.Response(data)
|
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(
|
@action(
|
||||||
detail=False,
|
detail=False,
|
||||||
methods=["get", "post"],
|
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"])
|
@pytest.mark.parametrize("f", ["json"])
|
||||||
def test_search3(f, db, logged_in_api_client, factories):
|
def test_search3(f, db, logged_in_api_client, factories):
|
||||||
url = reverse("api:subsonic-search3")
|
url = reverse("api:subsonic-search3")
|
||||||
|
|
Loading…
Reference in New Issue