kopia lustrzana https://dev.funkwhale.audio/funkwhale/funkwhale
See #432: can now start a radio from a tag
rodzic
3ce2f0d774
commit
918e7beb7e
|
@ -2,6 +2,7 @@ import random
|
|||
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import connection
|
||||
from django.db.models import Q
|
||||
from rest_framework import serializers
|
||||
|
||||
from funkwhale_api.moderation import filters as moderation_filters
|
||||
|
@ -14,6 +15,8 @@ from .registries import registry
|
|||
|
||||
|
||||
class SimpleRadio(object):
|
||||
related_object_field = None
|
||||
|
||||
def clean(self, instance):
|
||||
return
|
||||
|
||||
|
@ -146,6 +149,8 @@ class CustomRadio(SessionRadio):
|
|||
class RelatedObjectRadio(SessionRadio):
|
||||
"""Abstract radio related to an object (tag, artist, user...)"""
|
||||
|
||||
related_object_field = serializers.IntegerField(required=True)
|
||||
|
||||
def clean(self, instance):
|
||||
super().clean(instance)
|
||||
if not instance.related_object:
|
||||
|
@ -162,10 +167,22 @@ class RelatedObjectRadio(SessionRadio):
|
|||
@registry.register(name="tag")
|
||||
class TagRadio(RelatedObjectRadio):
|
||||
model = Tag
|
||||
related_object_field = serializers.CharField(required=True)
|
||||
|
||||
def get_related_object(self, name):
|
||||
return self.model.objects.get(name=name)
|
||||
|
||||
def get_queryset(self, **kwargs):
|
||||
qs = super().get_queryset(**kwargs)
|
||||
return qs.filter(tagged_items__tag=self.session.related_object)
|
||||
query = (
|
||||
Q(tagged_items__tag=self.session.related_object)
|
||||
| Q(artist__tagged_items__tag=self.session.related_object)
|
||||
| Q(album__tagged_items__tag=self.session.related_object)
|
||||
)
|
||||
return qs.filter(query)
|
||||
|
||||
def get_related_object_id_repr(self, obj):
|
||||
return obj.name
|
||||
|
||||
|
||||
def weighted_choice(choices):
|
||||
|
|
|
@ -54,6 +54,9 @@ class RadioSessionTrackSerializer(serializers.ModelSerializer):
|
|||
|
||||
|
||||
class RadioSessionSerializer(serializers.ModelSerializer):
|
||||
|
||||
related_object_id = serializers.CharField(required=False, allow_null=True)
|
||||
|
||||
class Meta:
|
||||
model = models.RadioSession
|
||||
fields = (
|
||||
|
@ -66,7 +69,17 @@ class RadioSessionSerializer(serializers.ModelSerializer):
|
|||
)
|
||||
|
||||
def validate(self, data):
|
||||
registry[data["radio_type"]]().validate_session(data, **self.context)
|
||||
radio_conf = registry[data["radio_type"]]()
|
||||
if radio_conf.related_object_field:
|
||||
try:
|
||||
data[
|
||||
"related_object_id"
|
||||
] = radio_conf.related_object_field.to_internal_value(
|
||||
data["related_object_id"]
|
||||
)
|
||||
except KeyError:
|
||||
raise serializers.ValidationError("Radio requires a related object")
|
||||
radio_conf.validate_session(data, **self.context)
|
||||
return data
|
||||
|
||||
def create(self, validated_data):
|
||||
|
@ -77,3 +90,11 @@ class RadioSessionSerializer(serializers.ModelSerializer):
|
|||
validated_data["related_object_id"]
|
||||
)
|
||||
return super().create(validated_data)
|
||||
|
||||
def to_representation(self, instance):
|
||||
repr = super().to_representation(instance)
|
||||
radio_conf = registry[repr["radio_type"]]()
|
||||
handler = getattr(radio_conf, "get_related_object_id_repr", None)
|
||||
if handler and instance.related_object:
|
||||
repr["related_object_id"] = handler(instance.related_object)
|
||||
return repr
|
||||
|
|
|
@ -197,16 +197,19 @@ def test_can_start_artist_radio(factories):
|
|||
|
||||
def test_can_start_tag_radio(factories):
|
||||
user = factories["users.User"]()
|
||||
factories["music.Upload"].create_batch(5)
|
||||
tag = factories["tags.Tag"]()
|
||||
good_files = factories["music.Upload"].create_batch(5, track__set_tags=[tag])
|
||||
good_tracks = [f.track for f in good_files]
|
||||
good_tracks = [
|
||||
factories["music.Track"](set_tags=[tag.name]),
|
||||
factories["music.Track"](album__set_tags=[tag.name]),
|
||||
factories["music.Track"](album__artist__set_tags=[tag.name]),
|
||||
]
|
||||
factories["music.Track"].create_batch(3, set_tags=["notrock"])
|
||||
|
||||
radio = radios.TagRadio()
|
||||
session = radio.start_session(user, related_object=tag)
|
||||
assert session.radio_type == "tag"
|
||||
|
||||
for i in range(5):
|
||||
for i in range(3):
|
||||
assert radio.pick(filter_playable=False) in good_tracks
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
from funkwhale_api.radios import serializers
|
||||
|
||||
|
||||
def test_create_tag_radio(factories):
|
||||
tag = factories["tags.Tag"]()
|
||||
|
||||
data = {"radio_type": "tag", "related_object_id": tag.name}
|
||||
|
||||
serializer = serializers.RadioSessionSerializer(data=data)
|
||||
assert serializer.is_valid(raise_exception=True) is True
|
||||
|
||||
session = serializer.save()
|
||||
|
||||
assert session.related_object_id == tag.pk
|
||||
assert session.related_object == tag
|
||||
|
||||
|
||||
def test_create_artist_radio(factories):
|
||||
artist = factories["music.Artist"]()
|
||||
|
||||
data = {"radio_type": "artist", "related_object_id": artist.pk}
|
||||
|
||||
serializer = serializers.RadioSessionSerializer(data=data)
|
||||
assert serializer.is_valid(raise_exception=True) is True
|
||||
|
||||
session = serializer.save()
|
||||
|
||||
assert session.related_object_id == artist.pk
|
||||
assert session.related_object == artist
|
||||
|
||||
|
||||
def test_tag_radio_repr(factories):
|
||||
tag = factories["tags.Tag"]()
|
||||
session = factories["radios.RadioSession"](related_object=tag, radio_type="tag")
|
||||
|
||||
expected = {
|
||||
"id": session.pk,
|
||||
"radio_type": "tag",
|
||||
"custom_radio": None,
|
||||
"user": session.user.pk,
|
||||
"related_object_id": tag.name,
|
||||
"creation_date": session.creation_date.isoformat().split("+")[0] + "Z",
|
||||
}
|
||||
assert serializers.RadioSessionSerializer(session).data == expected
|
|
@ -6,6 +6,7 @@
|
|||
{{ labels.title }}
|
||||
</span>
|
||||
</h2>
|
||||
<radio-button type="tag" :object-id="id"></radio-button>
|
||||
<div class="ui hidden divider"></div>
|
||||
<div class="ui row">
|
||||
<artist-widget :controls="false" :filters="{playable: true, ordering: '-creation_date', tag: id}">
|
||||
|
@ -39,10 +40,10 @@
|
|||
|
||||
<script>
|
||||
|
||||
|
||||
import TrackWidget from "@/components/audio/track/Widget"
|
||||
import AlbumWidget from "@/components/audio/album/Widget"
|
||||
import ArtistWidget from "@/components/audio/artist/Widget"
|
||||
import RadioButton from "@/components/radios/Button"
|
||||
|
||||
export default {
|
||||
props: {
|
||||
|
@ -52,6 +53,7 @@ export default {
|
|||
ArtistWidget,
|
||||
AlbumWidget,
|
||||
TrackWidget,
|
||||
RadioButton,
|
||||
},
|
||||
computed: {
|
||||
labels() {
|
||||
|
|
|
@ -12,7 +12,7 @@ export default {
|
|||
props: {
|
||||
customRadioId: {required: false},
|
||||
type: {type: String, required: false},
|
||||
objectId: {type: Number, default: null}
|
||||
objectId: {default: null}
|
||||
},
|
||||
methods: {
|
||||
toggleRadio () {
|
||||
|
|
Ładowanie…
Reference in New Issue