API Endpoint to list lirary tracks
This commit is contained in:
parent
bdf9347917
commit
57bf43bb96
|
@ -7,5 +7,9 @@ router.register(
|
||||||
r'libraries',
|
r'libraries',
|
||||||
views.LibraryViewSet,
|
views.LibraryViewSet,
|
||||||
'libraries')
|
'libraries')
|
||||||
|
router.register(
|
||||||
|
r'library-tracks',
|
||||||
|
views.LibraryTrackViewSet,
|
||||||
|
'library-tracks')
|
||||||
|
|
||||||
urlpatterns = router.urls
|
urlpatterns = router.urls
|
||||||
|
|
|
@ -17,6 +17,20 @@ class LibraryFilter(django_filters.FilterSet):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class LibraryTrackFilter(django_filters.FilterSet):
|
||||||
|
library = django_filters.CharFilter('library__uuid')
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = models.LibraryTrack
|
||||||
|
fields = {
|
||||||
|
'library': ['exact'],
|
||||||
|
'artist_name': ['exact', 'icontains'],
|
||||||
|
'title': ['exact', 'icontains'],
|
||||||
|
'album_title': ['exact', 'icontains'],
|
||||||
|
'audio_mimetype': ['exact', 'icontains'],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class FollowFilter(django_filters.FilterSet):
|
class FollowFilter(django_filters.FilterSet):
|
||||||
ordering = django_filters.OrderingFilter(
|
ordering = django_filters.OrderingFilter(
|
||||||
# tuple-mapping retains order
|
# tuple-mapping retains order
|
||||||
|
|
|
@ -253,6 +253,29 @@ class APILibraryCreateSerializer(serializers.ModelSerializer):
|
||||||
return library
|
return library
|
||||||
|
|
||||||
|
|
||||||
|
class APILibraryTrackSerializer(serializers.ModelSerializer):
|
||||||
|
library = APILibrarySerializer()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = models.LibraryTrack
|
||||||
|
fields = [
|
||||||
|
'id',
|
||||||
|
'url',
|
||||||
|
'audio_url',
|
||||||
|
'audio_mimetype',
|
||||||
|
'creation_date',
|
||||||
|
'modification_date',
|
||||||
|
'fetched_date',
|
||||||
|
'published_date',
|
||||||
|
'metadata',
|
||||||
|
'artist_name',
|
||||||
|
'album_title',
|
||||||
|
'title',
|
||||||
|
'library',
|
||||||
|
'local_track_file',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class FollowSerializer(serializers.Serializer):
|
class FollowSerializer(serializers.Serializer):
|
||||||
id = serializers.URLField()
|
id = serializers.URLField()
|
||||||
object = serializers.URLField()
|
object = serializers.URLField()
|
||||||
|
|
|
@ -2,6 +2,7 @@ import json
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
from requests.exceptions import RequestException
|
from requests.exceptions import RequestException
|
||||||
|
|
||||||
|
@ -58,6 +59,9 @@ def scan_library(library, until=None):
|
||||||
data = lb.get_library_data(library.url)
|
data = lb.get_library_data(library.url)
|
||||||
scan_library_page.delay(
|
scan_library_page.delay(
|
||||||
library_id=library.id, page_url=data['first'], until=until)
|
library_id=library.id, page_url=data['first'], until=until)
|
||||||
|
library.fetched_date = timezone.now()
|
||||||
|
library.tracks_count = data['totalItems']
|
||||||
|
library.save(update_fields=['fetched_date', 'tracks_count'])
|
||||||
|
|
||||||
|
|
||||||
@celery.app.task(
|
@celery.app.task(
|
||||||
|
|
|
@ -14,6 +14,7 @@ from rest_framework.decorators import list_route, detail_route
|
||||||
from rest_framework.serializers import ValidationError
|
from rest_framework.serializers import ValidationError
|
||||||
|
|
||||||
from funkwhale_api.common import utils as funkwhale_utils
|
from funkwhale_api.common import utils as funkwhale_utils
|
||||||
|
from funkwhale_api.common.permissions import HasModelPermission
|
||||||
from funkwhale_api.music.models import TrackFile
|
from funkwhale_api.music.models import TrackFile
|
||||||
|
|
||||||
from . import activity
|
from . import activity
|
||||||
|
@ -166,12 +167,16 @@ class MusicFilesViewSet(FederationMixin, viewsets.GenericViewSet):
|
||||||
return response.Response(data)
|
return response.Response(data)
|
||||||
|
|
||||||
|
|
||||||
|
class LibraryPermission(HasModelPermission):
|
||||||
|
model = models.Library
|
||||||
|
|
||||||
|
|
||||||
class LibraryViewSet(
|
class LibraryViewSet(
|
||||||
mixins.RetrieveModelMixin,
|
mixins.RetrieveModelMixin,
|
||||||
mixins.UpdateModelMixin,
|
mixins.UpdateModelMixin,
|
||||||
mixins.ListModelMixin,
|
mixins.ListModelMixin,
|
||||||
viewsets.GenericViewSet):
|
viewsets.GenericViewSet):
|
||||||
permission_classes = [rest_permissions.DjangoModelPermissions]
|
permission_classes = [LibraryPermission]
|
||||||
queryset = models.Library.objects.all().select_related(
|
queryset = models.Library.objects.all().select_related(
|
||||||
'actor',
|
'actor',
|
||||||
'follow',
|
'follow',
|
||||||
|
@ -184,6 +189,7 @@ class LibraryViewSet(
|
||||||
'creation_date',
|
'creation_date',
|
||||||
'fetched_date',
|
'fetched_date',
|
||||||
'actor__domain',
|
'actor__domain',
|
||||||
|
'tracks_count',
|
||||||
)
|
)
|
||||||
|
|
||||||
@list_route(methods=['get'])
|
@list_route(methods=['get'])
|
||||||
|
@ -203,11 +209,11 @@ class LibraryViewSet(
|
||||||
data=request.data
|
data=request.data
|
||||||
)
|
)
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
id = tasks.scan_library.delay(
|
result = tasks.scan_library.delay(
|
||||||
library_id=library.pk,
|
library_id=library.pk,
|
||||||
until=serializer.validated_data['until']
|
until=serializer.validated_data.get('until')
|
||||||
)
|
)
|
||||||
return response.Response({'task': id})
|
return response.Response({'task': result.id})
|
||||||
|
|
||||||
@list_route(methods=['get'])
|
@list_route(methods=['get'])
|
||||||
def following(self, request, *args, **kwargs):
|
def following(self, request, *args, **kwargs):
|
||||||
|
@ -249,3 +255,26 @@ class LibraryViewSet(
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
library = serializer.save()
|
library = serializer.save()
|
||||||
return response.Response(serializer.data, status=201)
|
return response.Response(serializer.data, status=201)
|
||||||
|
|
||||||
|
|
||||||
|
class LibraryTrackViewSet(
|
||||||
|
mixins.ListModelMixin,
|
||||||
|
viewsets.GenericViewSet):
|
||||||
|
permission_classes = [LibraryPermission]
|
||||||
|
queryset = models.LibraryTrack.objects.all().select_related(
|
||||||
|
'library__actor',
|
||||||
|
'library__follow',
|
||||||
|
'local_track_file',
|
||||||
|
)
|
||||||
|
filter_class = filters.LibraryTrackFilter
|
||||||
|
serializer_class = serializers.APILibraryTrackSerializer
|
||||||
|
ordering_fields = (
|
||||||
|
'id',
|
||||||
|
'artist_name',
|
||||||
|
'title',
|
||||||
|
'album_title',
|
||||||
|
'creation_date',
|
||||||
|
'modification_date',
|
||||||
|
'fetched_date',
|
||||||
|
'published_date',
|
||||||
|
)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from django.core.paginator import Paginator
|
from django.core.paginator import Paginator
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
from funkwhale_api.federation import serializers
|
from funkwhale_api.federation import serializers
|
||||||
from funkwhale_api.federation import tasks
|
from funkwhale_api.federation import tasks
|
||||||
|
@ -21,6 +22,7 @@ def test_scan_library_page_does_nothing_if_federation_disabled(
|
||||||
|
|
||||||
def test_scan_library_fetches_page_and_calls_scan_page(
|
def test_scan_library_fetches_page_and_calls_scan_page(
|
||||||
mocker, factories, r_mock):
|
mocker, factories, r_mock):
|
||||||
|
now = timezone.now()
|
||||||
library = factories['federation.Library'](federation_enabled=True)
|
library = factories['federation.Library'](federation_enabled=True)
|
||||||
collection_conf = {
|
collection_conf = {
|
||||||
'actor': library.actor,
|
'actor': library.actor,
|
||||||
|
@ -39,6 +41,8 @@ def test_scan_library_fetches_page_and_calls_scan_page(
|
||||||
page_url=collection.data['first'],
|
page_url=collection.data['first'],
|
||||||
until=None,
|
until=None,
|
||||||
)
|
)
|
||||||
|
library.refresh_from_db()
|
||||||
|
assert library.fetched_date > now
|
||||||
|
|
||||||
|
|
||||||
def test_scan_page_fetches_page_and_creates_tracks(
|
def test_scan_page_fetches_page_and_creates_tracks(
|
||||||
|
|
|
@ -312,7 +312,7 @@ def test_can_patch_library(factories, superuser_api_client):
|
||||||
def test_scan_library(factories, mocker, superuser_api_client):
|
def test_scan_library(factories, mocker, superuser_api_client):
|
||||||
scan = mocker.patch(
|
scan = mocker.patch(
|
||||||
'funkwhale_api.federation.tasks.scan_library.delay',
|
'funkwhale_api.federation.tasks.scan_library.delay',
|
||||||
return_value='id')
|
return_value=mocker.Mock(id='id'))
|
||||||
library = factories['federation.Library']()
|
library = factories['federation.Library']()
|
||||||
now = timezone.now()
|
now = timezone.now()
|
||||||
data = {
|
data = {
|
||||||
|
@ -329,3 +329,20 @@ def test_scan_library(factories, mocker, superuser_api_client):
|
||||||
library_id=library.pk,
|
library_id=library.pk,
|
||||||
until=now
|
until=now
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_list_library_tracks(factories, superuser_api_client):
|
||||||
|
library = factories['federation.Library']()
|
||||||
|
lts = list(reversed(factories['federation.LibraryTrack'].create_batch(
|
||||||
|
size=5, library=library)))
|
||||||
|
factories['federation.LibraryTrack'].create_batch(size=5)
|
||||||
|
url = reverse('api:v1:federation:library-tracks-list')
|
||||||
|
response = superuser_api_client.get(url, {'library': library.uuid})
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.data == {
|
||||||
|
'results': serializers.APILibraryTrackSerializer(lts, many=True).data,
|
||||||
|
'count': 5,
|
||||||
|
'previous': None,
|
||||||
|
'next': None,
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue